diff --git a/applications/external/flipbip/LICENSE b/applications/external/flipbip/LICENSE new file mode 100644 index 000000000..61361ecc7 --- /dev/null +++ b/applications/external/flipbip/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Struan Clark + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/applications/external/flipbip/application.fam b/applications/external/flipbip/application.fam new file mode 100644 index 000000000..ca340b22b --- /dev/null +++ b/applications/external/flipbip/application.fam @@ -0,0 +1,22 @@ +App( + appid="flipbip", + name="FlipBIP Crypto Tool", + apptype=FlipperAppType.EXTERNAL, + entry_point="flipbip_app", + requires=[ + "gui", + ], + stack_size=3 * 1024, + order=10, + fap_icon="flipbip_10px.png", + fap_icon_assets="icons", + fap_private_libs=[ + Lib( + name="crypto", + ), + ], + fap_category="Tools", + fap_description="Crypto toolkit for Flipper", + fap_author="Struan Clark (xtruan)", + fap_weburl="https://github.com/xtruan/FlipBIP", +) diff --git a/applications/external/flipbip/flipbip.c b/applications/external/flipbip/flipbip.c new file mode 100644 index 000000000..1a5e5a983 --- /dev/null +++ b/applications/external/flipbip/flipbip.c @@ -0,0 +1,205 @@ +#pragma GCC optimize("-Os") + +#include "flipbip.h" +#include "helpers/flipbip_file.h" +#include "helpers/flipbip_haptic.h" +// From: lib/crypto +#include +#include + +bool flipbip_custom_event_callback(void* context, uint32_t event) { + furi_assert(context); + FlipBip* app = context; + return scene_manager_handle_custom_event(app->scene_manager, event); +} + +void flipbip_tick_event_callback(void* context) { + furi_assert(context); + FlipBip* app = context; + scene_manager_handle_tick_event(app->scene_manager); +} + +//leave app if back button pressed +bool flipbip_navigation_event_callback(void* context) { + furi_assert(context); + FlipBip* app = context; + return scene_manager_handle_back_event(app->scene_manager); +} + +static void text_input_callback(void* context) { + furi_assert(context); + FlipBip* app = context; + bool handled = false; + + // check that there is text in the input + if(strlen(app->input_text) > 0) { + if(app->input_state == FlipBipTextInputPassphrase) { + if(app->passphrase == FlipBipPassphraseOn) { + strcpy(app->passphrase_text, app->input_text); + } + // clear input text + memzero(app->input_text, TEXT_BUFFER_SIZE); + // reset input state + app->input_state = FlipBipTextInputDefault; + handled = true; + view_dispatcher_switch_to_view(app->view_dispatcher, FlipBipViewIdSettings); + } else if(app->input_state == FlipBipTextInputMnemonic) { + if(app->import_from_mnemonic == 1) { + strcpy(app->import_mnemonic_text, app->input_text); + + int status = FlipBipStatusSuccess; + // Check if the mnemonic is valid + if(mnemonic_check(app->import_mnemonic_text) == 0) + status = FlipBipStatusMnemonicCheckError; // 13 = mnemonic check error + // Save the mnemonic to persistent storage + else if(!flipbip_save_file_secure(app->import_mnemonic_text)) + status = FlipBipStatusSaveError; // 12 = save error + + if(status == FlipBipStatusSuccess) { + //notification_message(app->notification, &sequence_blink_cyan_100); + flipbip_play_happy_bump(app); + } else { + //notification_message(app->notification, &sequence_blink_red_100); + flipbip_play_long_bump(app); + } + + memzero(app->import_mnemonic_text, TEXT_BUFFER_SIZE); + } + // clear input text + memzero(app->input_text, TEXT_BUFFER_SIZE); + // reset input state + app->input_state = FlipBipTextInputDefault; + handled = true; + view_dispatcher_switch_to_view(app->view_dispatcher, FlipBipViewIdMenu); + } + } + + if(!handled) { + // clear input text + memzero(app->input_text, TEXT_BUFFER_SIZE); + // reset input state + app->input_state = FlipBipTextInputDefault; + view_dispatcher_switch_to_view(app->view_dispatcher, FlipBipViewIdMenu); + } +} + +FlipBip* flipbip_app_alloc() { + FlipBip* app = malloc(sizeof(FlipBip)); + app->gui = furi_record_open(RECORD_GUI); + app->notification = furi_record_open(RECORD_NOTIFICATION); + + //Turn backlight on, believe me this makes testing your app easier + notification_message(app->notification, &sequence_display_backlight_on); + + //Scene additions + app->view_dispatcher = view_dispatcher_alloc(); + view_dispatcher_enable_queue(app->view_dispatcher); + + app->scene_manager = scene_manager_alloc(&flipbip_scene_handlers, app); + view_dispatcher_set_event_callback_context(app->view_dispatcher, app); + view_dispatcher_set_navigation_event_callback( + app->view_dispatcher, flipbip_navigation_event_callback); + view_dispatcher_set_tick_event_callback( + app->view_dispatcher, flipbip_tick_event_callback, 100); + view_dispatcher_set_custom_event_callback(app->view_dispatcher, flipbip_custom_event_callback); + app->submenu = submenu_alloc(); + + // Settings + app->haptic = FlipBipHapticOn; + app->led = FlipBipLedOn; + app->bip39_strength = FlipBipStrength256; // 256 bits (24 words) + app->passphrase = FlipBipPassphraseOff; + + // Main menu + app->bip44_coin = FlipBipCoinBTC0; // 0 (BTC) + app->overwrite_saved_seed = 0; + app->import_from_mnemonic = 0; + + // Text input + app->input_state = FlipBipTextInputDefault; + + view_dispatcher_add_view( + app->view_dispatcher, FlipBipViewIdMenu, submenu_get_view(app->submenu)); + app->flipbip_startscreen = flipbip_startscreen_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, + FlipBipViewIdStartscreen, + flipbip_startscreen_get_view(app->flipbip_startscreen)); + app->flipbip_scene_1 = flipbip_scene_1_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, FlipBipViewIdScene1, flipbip_scene_1_get_view(app->flipbip_scene_1)); + app->variable_item_list = variable_item_list_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, + FlipBipViewIdSettings, + variable_item_list_get_view(app->variable_item_list)); + + app->text_input = text_input_alloc(); + text_input_set_result_callback( + app->text_input, + text_input_callback, + (void*)app, + app->input_text, + TEXT_BUFFER_SIZE, + //clear default text + true); + text_input_set_header_text(app->text_input, "Input"); + view_dispatcher_add_view( + app->view_dispatcher, FlipBipViewIdTextInput, text_input_get_view(app->text_input)); + + //End Scene Additions + + return app; +} + +void flipbip_app_free(FlipBip* app) { + furi_assert(app); + + // Scene manager + scene_manager_free(app->scene_manager); + + text_input_free(app->text_input); + + // View Dispatcher + view_dispatcher_remove_view(app->view_dispatcher, FlipBipViewIdMenu); + view_dispatcher_remove_view(app->view_dispatcher, FlipBipViewIdScene1); + view_dispatcher_remove_view(app->view_dispatcher, FlipBipViewIdSettings); + view_dispatcher_remove_view(app->view_dispatcher, FlipBipViewIdTextInput); + submenu_free(app->submenu); + + view_dispatcher_free(app->view_dispatcher); + furi_record_close(RECORD_GUI); + + app->gui = NULL; + app->notification = NULL; + + //Remove whatever is left + memzero(app, sizeof(FlipBip)); + free(app); +} + +int32_t flipbip_app(void* p) { + UNUSED(p); + FlipBip* app = flipbip_app_alloc(); + + // Disabled because causes exit on custom firmwares such as RM + /*if(!furi_hal_region_is_provisioned()) { + flipbip_app_free(app); + return 1; + }*/ + + view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); + + scene_manager_next_scene( + app->scene_manager, FlipBipSceneStartscreen); //Start with start screen + //scene_manager_next_scene(app->scene_manager, FlipBipSceneMenu); //if you want to directly start with Menu + + furi_hal_power_suppress_charge_enter(); + + view_dispatcher_run(app->view_dispatcher); + + furi_hal_power_suppress_charge_exit(); + flipbip_app_free(app); + + return 0; +} diff --git a/applications/external/flipbip/flipbip.h b/applications/external/flipbip/flipbip.h new file mode 100644 index 000000000..6f84a1736 --- /dev/null +++ b/applications/external/flipbip/flipbip.h @@ -0,0 +1,99 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "scenes/flipbip_scene.h" +#include "views/flipbip_startscreen.h" +#include "views/flipbip_scene_1.h" + +#define FLIPBIP_VERSION "v0.0.9" + +#define COIN_BTC 0 +#define COIN_DOGE 3 +#define COIN_ETH 60 + +#define TEXT_BUFFER_SIZE 256 + +typedef struct { + Gui* gui; + NotificationApp* notification; + ViewDispatcher* view_dispatcher; + Submenu* submenu; + SceneManager* scene_manager; + VariableItemList* variable_item_list; + TextInput* text_input; + FlipBipStartscreen* flipbip_startscreen; + FlipBipScene1* flipbip_scene_1; + // Settings options + int haptic; + int led; + int bip39_strength; + int passphrase; + // Main menu options + int bip44_coin; + int overwrite_saved_seed; + int import_from_mnemonic; + // Text input + int input_state; + char passphrase_text[TEXT_BUFFER_SIZE]; + char import_mnemonic_text[TEXT_BUFFER_SIZE]; + char input_text[TEXT_BUFFER_SIZE]; +} FlipBip; + +typedef enum { + FlipBipViewIdStartscreen, + FlipBipViewIdMenu, + FlipBipViewIdScene1, + FlipBipViewIdSettings, + FlipBipViewIdTextInput, +} FlipBipViewId; + +typedef enum { + FlipBipHapticOff, + FlipBipHapticOn, +} FlipBipHapticState; + +typedef enum { + FlipBipLedOff, + FlipBipLedOn, +} FlipBipLedState; + +typedef enum { + FlipBipStrength128, + FlipBipStrength192, + FlipBipStrength256, +} FlipBipStrengthState; + +typedef enum { + FlipBipPassphraseOff, + FlipBipPassphraseOn, +} FlipBipPassphraseState; + +typedef enum { + FlipBipCoinBTC0, + FlipBipCoinETH60, + FlipBipCoinDOGE3, +} FlipBipCoin; + +typedef enum { + FlipBipTextInputDefault, + FlipBipTextInputPassphrase, + FlipBipTextInputMnemonic +} FlipBipTextInputState; + +typedef enum { + FlipBipStatusSuccess = 0, + FlipBipStatusReturn = 10, + FlipBipStatusLoadError = 11, + FlipBipStatusSaveError = 12, + FlipBipStatusMnemonicCheckError = 13, +} FlipBipStatus; diff --git a/applications/external/flipbip/flipbip_10px.png b/applications/external/flipbip/flipbip_10px.png new file mode 100644 index 000000000..173079046 Binary files /dev/null and b/applications/external/flipbip/flipbip_10px.png differ diff --git a/applications/external/flipbip/helpers/flipbip_custom_event.h b/applications/external/flipbip/helpers/flipbip_custom_event.h new file mode 100644 index 000000000..2dbaf5112 --- /dev/null +++ b/applications/external/flipbip/helpers/flipbip_custom_event.h @@ -0,0 +1,16 @@ +#pragma once + +typedef enum { + FlipBipCustomEventStartscreenUp, + FlipBipCustomEventStartscreenDown, + FlipBipCustomEventStartscreenLeft, + FlipBipCustomEventStartscreenRight, + FlipBipCustomEventStartscreenOk, + FlipBipCustomEventStartscreenBack, + FlipBipCustomEventScene1Up, + FlipBipCustomEventScene1Down, + FlipBipCustomEventScene1Left, + FlipBipCustomEventScene1Right, + FlipBipCustomEventScene1Ok, + FlipBipCustomEventScene1Back, +} FlipBipCustomEvent; \ No newline at end of file diff --git a/applications/external/flipbip/helpers/flipbip_file.c b/applications/external/flipbip/helpers/flipbip_file.c new file mode 100644 index 000000000..3b61b6b95 --- /dev/null +++ b/applications/external/flipbip/helpers/flipbip_file.c @@ -0,0 +1,309 @@ +#include "flipbip_file.h" +#include +#include +#include +#include "../helpers/flipbip_string.h" +// From: lib/crypto +#include +#include + +// #define FLIPBIP_APP_BASE_FOLDER APP_DATA_PATH("flipbip") +#define FLIPBIP_APP_BASE_FOLDER EXT_PATH("apps_data/flipbip") +#define FLIPBIP_APP_BASE_FOLDER_PATH(path) FLIPBIP_APP_BASE_FOLDER "/" path +#define FLIPBIP_DAT_FILE_NAME ".flipbip.dat" +// #define FLIPBIP_DAT_FILE_NAME ".flipbip.dat.txt" +#define FLIPBIP_DAT_FILE_NAME_BAK ".flipbip.dat.bak" +#define FLIPBIP_KEY_FILE_NAME ".flipbip.key" +// #define FLIPBIP_KEY_FILE_NAME ".flipbip.key.txt" +#define FLIPBIP_KEY_FILE_NAME_BAK ".flipbip.key.bak" +#define FLIPBIP_DAT_PATH FLIPBIP_APP_BASE_FOLDER_PATH(FLIPBIP_DAT_FILE_NAME) +#define FLIPBIP_DAT_PATH_BAK FLIPBIP_APP_BASE_FOLDER_PATH(FLIPBIP_DAT_FILE_NAME_BAK) +#define FLIPBIP_KEY_PATH FLIPBIP_APP_BASE_FOLDER_PATH(FLIPBIP_KEY_FILE_NAME) +#define FLIPBIP_KEY_PATH_BAK FLIPBIP_APP_BASE_FOLDER_PATH(FLIPBIP_KEY_FILE_NAME_BAK) + +const char* TEXT_QRFILE = "Filetype: QRCode\n" + "Version: 0\n" + "Message: "; // 37 chars + 1 null +#define FILE_HLEN 4 +#define FILE_KLEN 256 +#define FILE_SLEN 512 +#define FILE_MAX_PATH_LEN 48 +#define FILE_MAX_QRFILE_CONTENT 90 +const char* FILE_HSTR = "fb01"; +const char* FILE_K1 = "fb0131d5cf688221c109163908ebe51debb46227c6cc8b37641910833222772a" + "baefe6d9ceb651842260e0d1e05e3b90d15e7d5ffaaabc0207bf200a117793a2"; + +bool flipbip_load_file(char* settings, const FlipBipFile file_type, const char* file_name) { + bool ret = false; + const char* path; + if(file_type == FlipBipFileKey) { + path = FLIPBIP_KEY_PATH; + } else if(file_type == FlipBipFileDat) { + path = FLIPBIP_DAT_PATH; + } else { + char path_buf[FILE_MAX_PATH_LEN] = {0}; + strcpy(path_buf, FLIPBIP_APP_BASE_FOLDER); // 22 + strcpy(path_buf + strlen(path_buf), "/"); + strcpy(path_buf + strlen(path_buf), file_name); + path = path_buf; + } + + Storage* fs_api = furi_record_open(RECORD_STORAGE); + + File* settings_file = storage_file_alloc(fs_api); + if(storage_file_open(settings_file, path, FSAM_READ, FSOM_OPEN_EXISTING)) { + char chr; + int i = 0; + while((storage_file_read(settings_file, &chr, 1) == 1) && + !storage_file_eof(settings_file) && !isspace(chr)) { + settings[i] = chr; + i++; + } + ret = true; + } else { + memzero(settings, strlen(settings)); + settings[0] = '\0'; + ret = false; + } + storage_file_close(settings_file); + storage_file_free(settings_file); + furi_record_close(RECORD_STORAGE); + + if(strlen(settings) > 0) { + Storage* fs_api = furi_record_open(RECORD_STORAGE); + FileInfo layout_file_info; + FS_Error file_check_err = storage_common_stat(fs_api, path, &layout_file_info); + furi_record_close(RECORD_STORAGE); + if(file_check_err != FSE_OK) { + memzero(settings, strlen(settings)); + settings[0] = '\0'; + ret = false; + } + // if(layout_file_info.size != 256) { + // memzero(settings, strlen(settings)); + // settings[0] = '\0'; + // } + } + + return ret; +} + +bool flipbip_has_file(const FlipBipFile file_type, const char* file_name, const bool remove) { + bool ret = false; + const char* path; + if(file_type == FlipBipFileKey) { + path = FLIPBIP_KEY_PATH; + } else if(file_type == FlipBipFileDat) { + path = FLIPBIP_DAT_PATH; + } else { + char path_buf[FILE_MAX_PATH_LEN] = {0}; + strcpy(path_buf, FLIPBIP_APP_BASE_FOLDER); // 22 + strcpy(path_buf + strlen(path_buf), "/"); + strcpy(path_buf + strlen(path_buf), file_name); + path = path_buf; + } + + Storage* fs_api = furi_record_open(RECORD_STORAGE); + if(remove) { + ret = storage_simply_remove(fs_api, path); + } else { + ret = storage_file_exists(fs_api, path); + } + furi_record_close(RECORD_STORAGE); + + return ret; +} + +bool flipbip_save_file( + const char* settings, + const FlipBipFile file_type, + const char* file_name, + const bool append) { + bool ret = false; + const char* path; + const char* path_bak; + if(file_type == FlipBipFileKey) { + path = FLIPBIP_KEY_PATH; + path_bak = FLIPBIP_KEY_PATH_BAK; + } else if(file_type == FlipBipFileDat) { + path = FLIPBIP_DAT_PATH; + path_bak = FLIPBIP_DAT_PATH_BAK; + } else { + char path_buf[FILE_MAX_PATH_LEN] = {0}; + strcpy(path_buf, FLIPBIP_APP_BASE_FOLDER); // 22 + strcpy(path_buf + strlen(path_buf), "/"); + strcpy(path_buf + strlen(path_buf), file_name); + path = path_buf; + path_bak = NULL; + } + int open_mode = FSOM_OPEN_ALWAYS; + if(append) { + open_mode = FSOM_OPEN_APPEND; + } + + Storage* fs_api = furi_record_open(RECORD_STORAGE); + // // if the key file exists, we don't want to overwrite it + // if (key_file && storage_file_exists(fs_api, path)) { + // furi_record_close(RECORD_STORAGE); + // ret = true; + // return ret; + // } + // try to create the folder + storage_simply_mkdir(fs_api, FLIPBIP_APP_BASE_FOLDER); + + File* settings_file = storage_file_alloc(fs_api); + if(storage_file_open(settings_file, path, FSAM_WRITE, open_mode)) { + storage_file_write(settings_file, settings, strlen(settings)); + storage_file_write(settings_file, "\n", 1); + ret = true; + } + storage_file_close(settings_file); + storage_file_free(settings_file); + + if(path_bak != NULL) { + File* settings_file_bak = storage_file_alloc(fs_api); + if(storage_file_open(settings_file_bak, path_bak, FSAM_WRITE, open_mode)) { + storage_file_write(settings_file_bak, settings, strlen(settings)); + storage_file_write(settings_file_bak, "\n", 1); + } + storage_file_close(settings_file_bak); + storage_file_free(settings_file_bak); + } + + furi_record_close(RECORD_STORAGE); + + return ret; +} + +bool flipbip_save_qrfile( + const char* qr_msg_prefix, + const char* qr_msg_content, + const char* file_name) { + char qr_buf[FILE_MAX_QRFILE_CONTENT] = {0}; + strcpy(qr_buf, TEXT_QRFILE); + strcpy(qr_buf + strlen(qr_buf), qr_msg_prefix); + strcpy(qr_buf + strlen(qr_buf), qr_msg_content); + return flipbip_save_file(qr_buf, FlipBipFileOther, file_name, false); +} + +bool flipbip_load_file_secure(char* settings) { + const size_t dlen = FILE_HLEN + FILE_SLEN + 1; + + // allocate memory for key/data + char* data = malloc(dlen); + memzero(data, dlen); + + // load k2 from file + if(!flipbip_load_file(data, FlipBipFileKey, NULL)) return false; + + // check header + if(data[0] != FILE_HSTR[0] || data[1] != FILE_HSTR[1] || data[2] != FILE_HSTR[2] || + data[3] != FILE_HSTR[3]) { + memzero(data, dlen); + free(data); + return false; + } + // seek --> header + data += FILE_HLEN; + + // prepare k1 + uint8_t k1[64]; + flipbip_xtob(FILE_K1, k1, strlen(FILE_K1) / 2); + + // load k2 from file buffer (secured by k1) + flipbip_cipher(k1, strlen(FILE_K1) / 2, data, data, FILE_KLEN); + uint8_t k2[128]; + flipbip_xtob(data, k2, FILE_KLEN / 2); + // zero k2 buffer + memzero(data, FILE_KLEN); + // seek <-- header + data -= FILE_HLEN; + + // load data from file + if(!flipbip_load_file(data, FlipBipFileDat, NULL)) return false; + + // check header + if(data[0] != FILE_HSTR[0] || data[1] != FILE_HSTR[1] || data[2] != FILE_HSTR[2] || + data[3] != FILE_HSTR[3]) { + memzero(data, dlen); + free(data); + memzero(k1, strlen(FILE_K1) / 2); + memzero(k2, FILE_KLEN / 2); + return false; + } + // seek --> header + data += FILE_HLEN; + + // load settings from file buffer (secured by k2) + flipbip_cipher(k2, FILE_KLEN / 2, data, data, FILE_SLEN); + flipbip_xtob(data, (unsigned char*)data, FILE_SLEN / 2); + + // copy to output + strcpy(settings, data); + + // seek <-- header + data -= FILE_HLEN; + + // clear memory + memzero(data, dlen); + free(data); + memzero(k1, strlen(FILE_K1) / 2); + memzero(k2, FILE_KLEN / 2); + + return true; +} + +bool flipbip_save_file_secure(const char* settings) { + const size_t dlen = FILE_HLEN + FILE_SLEN + 1; + + // cap settings to 256 bytes + size_t len = strlen(settings); + if(len > (FILE_SLEN / 2)) len = FILE_SLEN / 2; + + // allocate memory for key/data + char* data = malloc(dlen); + memzero(data, dlen); + + // write header + strncpy(data, FILE_HSTR, FILE_HLEN); + // seek --> header + data += FILE_HLEN; + + // prepare k1 + uint8_t k1[64]; + flipbip_xtob(FILE_K1, k1, strlen(FILE_K1) / 2); + + // generate k2 + uint8_t k2[128]; + random_buffer(k2, FILE_KLEN / 2); + + // write k2 to file buffer (secured by k1) + flipbip_btox(k2, FILE_KLEN / 2, data); + flipbip_cipher(k1, strlen(FILE_K1) / 2, data, data, FILE_KLEN); + + // seek <-- header + data -= FILE_HLEN; + // save k2 to file + flipbip_save_file(data, FlipBipFileKey, NULL, false); + // seek --> header + data += FILE_HLEN; + // zero k2 memory + memzero(data, FILE_KLEN); + + // write settings to file buffer (secured by k2) + flipbip_btox((uint8_t*)settings, len, data); + flipbip_cipher(k2, FILE_KLEN / 2, data, data, FILE_SLEN); + + // seek <-- header + data -= FILE_HLEN; + // save data to file + flipbip_save_file(data, FlipBipFileDat, NULL, false); + + // clear memory + memzero(data, dlen); + free(data); + memzero(k1, strlen(FILE_K1) / 2); + memzero(k2, FILE_KLEN / 2); + + return true; +} diff --git a/applications/external/flipbip/helpers/flipbip_file.h b/applications/external/flipbip/helpers/flipbip_file.h new file mode 100644 index 000000000..c19f70dc5 --- /dev/null +++ b/applications/external/flipbip/helpers/flipbip_file.h @@ -0,0 +1,23 @@ +#include + +typedef enum { + FlipBipFileDat, + FlipBipFileKey, + FlipBipFileOther, +} FlipBipFile; + +bool flipbip_has_file(const FlipBipFile file_type, const char* file_name, const bool remove); +bool flipbip_load_file(char* settings, const FlipBipFile file_type, const char* file_name); +bool flipbip_save_file( + const char* settings, + const FlipBipFile file_type, + const char* file_name, + const bool append); + +bool flipbip_save_qrfile( + const char* qr_msg_prefix, + const char* qr_msg_content, + const char* file_name); + +bool flipbip_load_file_secure(char* settings); +bool flipbip_save_file_secure(const char* settings); diff --git a/applications/external/flipbip/helpers/flipbip_haptic.c b/applications/external/flipbip/helpers/flipbip_haptic.c new file mode 100644 index 000000000..c5608efa5 --- /dev/null +++ b/applications/external/flipbip/helpers/flipbip_haptic.c @@ -0,0 +1,35 @@ +#include "flipbip_haptic.h" +#include "../flipbip.h" + +void flipbip_play_happy_bump(void* context) { + FlipBip* app = context; + if(app->haptic != 1) { + return; + } + notification_message(app->notification, &sequence_set_vibro_on); + furi_thread_flags_wait(0, FuriFlagWaitAny, 20); + notification_message(app->notification, &sequence_reset_vibro); +} + +void flipbip_play_bad_bump(void* context) { + FlipBip* app = context; + if(app->haptic != 1) { + return; + } + notification_message(app->notification, &sequence_set_vibro_on); + furi_thread_flags_wait(0, FuriFlagWaitAny, 100); + notification_message(app->notification, &sequence_reset_vibro); +} + +void flipbip_play_long_bump(void* context) { + FlipBip* app = context; + if(app->haptic != 1) { + return; + } + for(int i = 0; i < 4; i++) { + notification_message(app->notification, &sequence_set_vibro_on); + furi_thread_flags_wait(0, FuriFlagWaitAny, 50); + notification_message(app->notification, &sequence_reset_vibro); + furi_thread_flags_wait(0, FuriFlagWaitAny, 100); + } +} diff --git a/applications/external/flipbip/helpers/flipbip_haptic.h b/applications/external/flipbip/helpers/flipbip_haptic.h new file mode 100644 index 000000000..cab1d3a63 --- /dev/null +++ b/applications/external/flipbip/helpers/flipbip_haptic.h @@ -0,0 +1,7 @@ +#include + +void flipbip_play_happy_bump(void* context); + +void flipbip_play_bad_bump(void* context); + +void flipbip_play_long_bump(void* context); diff --git a/applications/external/flipbip/helpers/flipbip_led.c b/applications/external/flipbip/helpers/flipbip_led.c new file mode 100644 index 000000000..7a6fd1778 --- /dev/null +++ b/applications/external/flipbip/helpers/flipbip_led.c @@ -0,0 +1,39 @@ +#include "flipbip_led.h" +#include "../flipbip.h" + +void flipbip_led_set_rgb(void* context, int red, int green, int blue) { + FlipBip* app = context; + if(app->led != 1) { + return; + } + NotificationMessage notification_led_message_1; + notification_led_message_1.type = NotificationMessageTypeLedRed; + NotificationMessage notification_led_message_2; + notification_led_message_2.type = NotificationMessageTypeLedGreen; + NotificationMessage notification_led_message_3; + notification_led_message_3.type = NotificationMessageTypeLedBlue; + + notification_led_message_1.data.led.value = red; + notification_led_message_2.data.led.value = green; + notification_led_message_3.data.led.value = blue; + const NotificationSequence notification_sequence = { + ¬ification_led_message_1, + ¬ification_led_message_2, + ¬ification_led_message_3, + &message_do_not_reset, + NULL, + }; + notification_message(app->notification, ¬ification_sequence); + furi_thread_flags_wait( + 0, FuriFlagWaitAny, 10); //Delay, prevent removal from RAM before LED value set +} + +void flipbip_led_reset(void* context) { + FlipBip* app = context; + notification_message(app->notification, &sequence_reset_red); + notification_message(app->notification, &sequence_reset_green); + notification_message(app->notification, &sequence_reset_blue); + + furi_thread_flags_wait( + 0, FuriFlagWaitAny, 300); //Delay, prevent removal from RAM before LED value set +} diff --git a/applications/external/flipbip/helpers/flipbip_led.h b/applications/external/flipbip/helpers/flipbip_led.h new file mode 100644 index 000000000..bbacc976b --- /dev/null +++ b/applications/external/flipbip/helpers/flipbip_led.h @@ -0,0 +1,2 @@ +void flipbip_led_set_rgb(void* context, int red, int green, int blue); +void flipbip_led_reset(void* context); diff --git a/applications/external/flipbip/helpers/flipbip_speaker.c b/applications/external/flipbip/helpers/flipbip_speaker.c new file mode 100644 index 000000000..f7ae2193b --- /dev/null +++ b/applications/external/flipbip/helpers/flipbip_speaker.c @@ -0,0 +1,27 @@ +// #include "flipbip_speaker.h" +// #include "../flipbip.h" + +// #define NOTE_INPUT 587.33f + +// void flipbip_play_input_sound(void* context) { +// FlipBip* app = context; +// if (app->speaker != 1) { +// return; +// } +// float volume = 1.0f; +// if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(30)) { +// furi_hal_speaker_start(NOTE_INPUT, volume); +// } + +// } + +// void flipbip_stop_all_sound(void* context) { +// FlipBip* app = context; +// if (app->speaker != 1) { +// return; +// } +// if(furi_hal_speaker_is_mine()) { +// furi_hal_speaker_stop(); +// furi_hal_speaker_release(); +// } +// } diff --git a/applications/external/flipbip/helpers/flipbip_speaker.h b/applications/external/flipbip/helpers/flipbip_speaker.h new file mode 100644 index 000000000..150ba9129 --- /dev/null +++ b/applications/external/flipbip/helpers/flipbip_speaker.h @@ -0,0 +1,4 @@ +// #define NOTE_INPUT 587.33f + +// void flipbip_play_input_sound(void* context); +// void flipbip_stop_all_sound(void* context); diff --git a/applications/external/flipbip/helpers/flipbip_string.c b/applications/external/flipbip/helpers/flipbip_string.c new file mode 100644 index 000000000..999820646 --- /dev/null +++ b/applications/external/flipbip/helpers/flipbip_string.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 1988 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include "flipbip_string.h" +#include +#include +#include +// From: lib/crypto +#include +#include + +char* flipbip_strtok(char* s, const char* delim) { + static char* last; + return flipbip_strtok_r(s, delim, &last); +} +char* flipbip_strtok_r(char* s, const char* delim, char** last) { + char* spanp; + int c, sc; + char* tok; + if(s == NULL && (s = *last) == NULL) return (NULL); + /* + * Skip (span) leading delimiters (s += strspn(s, delim), sort of). + */ +cont: + c = *s++; + for(spanp = (char*)delim; (sc = *spanp++) != 0;) { + if(c == sc) goto cont; + } + if(c == 0) { /* no non-delimiter characters */ + *last = NULL; + return (NULL); + } + tok = s - 1; + /* + * Scan token (scan for delimiters: s += strcspn(s, delim), sort of). + * Note that delim must have one NUL; we stop if we see that, too. + */ + for(;;) { + c = *s++; + spanp = (char*)delim; + do { + if((sc = *spanp++) == c) { + if(c == 0) + s = NULL; + else + s[-1] = 0; + *last = s; + return (tok); + } + } while(sc != 0); + } + /* NOTREACHED */ +} + +void flipbip_btox(const unsigned char* in, int in_len, char* str) { + for(int i = 0; i < in_len; i++) { + unsigned char n; + unsigned char x = in[i]; + + str += 2; + *(str + (i * 2)) = '\0'; + + for(n = 2; n != 0; --n) { + *(--str + (i * 2)) = "0123456789abcdef"[x & 0x0F]; + x >>= 4; + } + } +} +void flipbip_xtob(const char* str, unsigned char* out, int out_len) { + int len = strlen(str) / 2; + if(len > out_len) len = out_len; + for(int i = 0; i < len; i++) { + char c = 0; + if(str[i * 2] >= '0' && str[i * 2] <= '9') c += (str[i * 2] - '0') << 4; + if((str[i * 2] & ~0x20) >= 'A' && (str[i * 2] & ~0x20) <= 'F') + c += (10 + (str[i * 2] & ~0x20) - 'A') << 4; + if(str[i * 2 + 1] >= '0' && str[i * 2 + 1] <= '9') c += (str[i * 2 + 1] - '0'); + if((str[i * 2 + 1] & ~0x20) >= 'A' && (str[i * 2 + 1] & ~0x20) <= 'F') + c += (10 + (str[i * 2 + 1] & ~0x20) - 'A'); + out[i] = c; + } +} + +void flipbip_cipher( + const unsigned char* key_in, + const unsigned int key_len, + const char* in, + char* out, + const unsigned int io_len) { + if(io_len > 512) return; + + RC4_CTX ctx; + uint8_t buf[256]; + memzero(buf, 256); + + flipbip_xtob(in, buf, io_len / 2); + + rc4_init(&ctx, key_in, key_len); + rc4_encrypt(&ctx, buf, 256); + + flipbip_btox(buf, io_len / 2, out); + + memzero(buf, 256); +} \ No newline at end of file diff --git a/applications/external/flipbip/helpers/flipbip_string.h b/applications/external/flipbip/helpers/flipbip_string.h new file mode 100644 index 000000000..a66bf7572 --- /dev/null +++ b/applications/external/flipbip/helpers/flipbip_string.h @@ -0,0 +1,12 @@ +char* flipbip_strtok(char* s, const char* delim); +char* flipbip_strtok_r(char* s, const char* delim, char** last); + +void flipbip_btox(const unsigned char* in, int in_len, char* str); +void flipbip_xtob(const char* str, unsigned char* out, int out_len); + +void flipbip_cipher( + const unsigned char* key_in, + const unsigned int key_len, + const char* in, + char* out, + const unsigned int io_len); \ No newline at end of file diff --git a/applications/external/flipbip/icons/Auth_62x31.png b/applications/external/flipbip/icons/Auth_62x31.png new file mode 100644 index 000000000..40f094ac9 Binary files /dev/null and b/applications/external/flipbip/icons/Auth_62x31.png differ diff --git a/applications/external/flipbip/icons/ButtonCenter_7x7.png b/applications/external/flipbip/icons/ButtonCenter_7x7.png new file mode 100644 index 000000000..a66461b22 Binary files /dev/null and b/applications/external/flipbip/icons/ButtonCenter_7x7.png differ diff --git a/applications/external/flipbip/icons/ButtonDown_10x5.png b/applications/external/flipbip/icons/ButtonDown_10x5.png new file mode 100644 index 000000000..b492b926c Binary files /dev/null and b/applications/external/flipbip/icons/ButtonDown_10x5.png differ diff --git a/applications/external/flipbip/icons/ButtonLeftSmall_3x5.png b/applications/external/flipbip/icons/ButtonLeftSmall_3x5.png new file mode 100644 index 000000000..51411acaf Binary files /dev/null and b/applications/external/flipbip/icons/ButtonLeftSmall_3x5.png differ diff --git a/applications/external/flipbip/icons/ButtonLeft_4x7.png b/applications/external/flipbip/icons/ButtonLeft_4x7.png new file mode 100644 index 000000000..0b4655d43 Binary files /dev/null and b/applications/external/flipbip/icons/ButtonLeft_4x7.png differ diff --git a/applications/external/flipbip/icons/ButtonRightSmall_3x5.png b/applications/external/flipbip/icons/ButtonRightSmall_3x5.png new file mode 100644 index 000000000..b9d5f87db Binary files /dev/null and b/applications/external/flipbip/icons/ButtonRightSmall_3x5.png differ diff --git a/applications/external/flipbip/icons/ButtonRight_4x7.png b/applications/external/flipbip/icons/ButtonRight_4x7.png new file mode 100644 index 000000000..8e1c74c1c Binary files /dev/null and b/applications/external/flipbip/icons/ButtonRight_4x7.png differ diff --git a/applications/external/flipbip/icons/ButtonUp_10x5.png b/applications/external/flipbip/icons/ButtonUp_10x5.png new file mode 100644 index 000000000..5da99d01e Binary files /dev/null and b/applications/external/flipbip/icons/ButtonUp_10x5.png differ diff --git a/applications/external/flipbip/icons/Keychain_39x36.png b/applications/external/flipbip/icons/Keychain_39x36.png new file mode 100644 index 000000000..d15850b5b Binary files /dev/null and b/applications/external/flipbip/icons/Keychain_39x36.png differ diff --git a/applications/external/flipbip/lib/crypto/AUTHORS b/applications/external/flipbip/lib/crypto/AUTHORS new file mode 100644 index 000000000..51c9bdab0 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/AUTHORS @@ -0,0 +1,2 @@ +Tomas Dzetkulic +Pavol Rusnak diff --git a/applications/external/flipbip/lib/crypto/CONTRIBUTORS b/applications/external/flipbip/lib/crypto/CONTRIBUTORS new file mode 100644 index 000000000..300b9788d --- /dev/null +++ b/applications/external/flipbip/lib/crypto/CONTRIBUTORS @@ -0,0 +1,16 @@ +Tomas Dzetkulic +Pavol Rusnak +Jochen Hoenicke +Dustin Laurence +Ondrej Mikle +Roman Zeyde +Alex Beregszaszi +netanelkl +Jan Pochyla +Ondrej Mikle +Josh Billings +Adam Mackler +Oleg Andreev +mog +John Dvorak +Christian Reitter diff --git a/applications/external/flipbip/lib/crypto/LICENSE b/applications/external/flipbip/lib/crypto/LICENSE new file mode 100644 index 000000000..1ea1df703 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2013 Tomas Dzetkulic +Copyright (c) 2013 Pavol Rusnak + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/applications/external/flipbip/lib/crypto/Makefile b/applications/external/flipbip/lib/crypto/Makefile new file mode 100644 index 000000000..2bdfc9417 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/Makefile @@ -0,0 +1,187 @@ +# CLANG_VERSION is empty if the compiler is not clang-based +CLANG_VERSION = $(shell $(CC) --version | sed -nr 's/^.*clang version ([0-9.]+).*$$/\1/p') +CLANG_VERSION_MAJOR = $(shell echo $(CLANG_VERSION) | cut -f1 -d.) + +# determine specific version ranges +ifneq ($(CLANG_VERSION),) +$(if $(shell [ $(CLANG_VERSION_MAJOR) -ge 13 ] && echo "OK"), \ + $(eval CLANG_AT_LEAST_13 := true), \ + $(eval CLANG_AT_LEAST_13 := false)) +endif + +ifeq ($(FUZZER),1) +CC ?= clang +LD ?= $(CC) +SANFLAGS += -fsanitize=fuzzer + +# only clang versions >= 13 support this feature +ifeq ($(CLANG_AT_LEAST_13),true) +$(info "info: using -fsanitize-ignorelist") +SANFLAGS += -fsanitize-ignorelist=fuzzer/sanitizer_ignorelist.txt +else +$(info "info: not using -fsanitize-ignorelist") +endif + +# TODO is there a better solution, for example by disabling a specific optimization technique? +# there is a clang optimization issue in relation with the blake2 code at -fsanitize=undefined +$(warning "warning: disabling optimization on blake2 code as workaround") +blake2b.o: OPTFLAGS += -O0 +blake2s.o: OPTFLAGS += -O0 + +else ifeq ($(ADDRESS_SANITIZER),1) +SANFLAGS += -fsanitize=address,undefined +endif + +CC ?= cc + +OPTFLAGS ?= -O3 -g + +CFLAGS += $(OPTFLAGS) \ + $(SANFLAGS) \ + -std=gnu99 \ + -W \ + -Wall \ + -Wextra \ + -Wimplicit-function-declaration \ + -Wredundant-decls \ + -Wstrict-prototypes \ + -Wundef \ + -Wshadow \ + -Wpointer-arith \ + -Wformat \ + -Wreturn-type \ + -Wsign-compare \ + -Wmultichar \ + -Wformat-nonliteral \ + -Winit-self \ + -Wuninitialized \ + -Wformat-security \ + -Wno-missing-braces \ + -Werror + +ZKP_CFLAGS = \ + -DECMULT_GEN_PREC_BITS=4 \ + -DECMULT_WINDOW_SIZE=8 \ + -DENABLE_MODULE_GENERATOR \ + -DENABLE_MODULE_RECOVERY \ + -DENABLE_MODULE_SCHNORRSIG \ + -DENABLE_MODULE_EXTRAKEYS +ZKP_PATH = ../vendor/secp256k1-zkp +# this is specific for 64-bit builds +CFLAGS += -DSECP256K1_CONTEXT_SIZE=208 + +VALGRIND ?= 1 +ifeq ($(VALGRIND),1) +CFLAGS += -DVALGRIND +endif + +CFLAGS += -I. +CFLAGS += -I.. +CFLAGS += -DUSE_ETHEREUM=1 +CFLAGS += -DUSE_KECCAK=1 +CFLAGS += -DUSE_MONERO=1 +CFLAGS += -DUSE_NEM=1 +CFLAGS += -DUSE_CARDANO=1 +CFLAGS += $(shell pkg-config --cflags openssl) + +# disable certain optimizations and features when small footprint is required +ifdef SMALL +CFLAGS += -DUSE_PRECOMPUTED_CP=0 +endif + +SRCS = bignum.c ecdsa.c curves.c secp256k1.c nist256p1.c rand.c hmac.c bip32.c bip39.c bip39_english.c pbkdf2.c base58.c base32.c +SRCS += address.c +SRCS += script.c +SRCS += ripemd160.c +SRCS += sha2.c +SRCS += sha3.c +SRCS += hasher.c +SRCS += aes/aescrypt.c aes/aeskey.c aes/aestab.c aes/aes_modes.c +SRCS += ed25519_donna/curve25519_donna_32bit.c ed25519_donna/curve25519_donna_helpers.c ed25519_donna/modm_donna_32bit.c +SRCS += ed25519_donna/ed25519_donna_basepoint_table.c ed25519_donna/ed25519_donna_32bit_tables.c ed25519_donna/ed25519_donna_impl_base.c +SRCS += ed25519_donna/ed25519.c ed25519_donna/curve25519_donna_scalarmult_base.c ed25519_donna/ed25519_sha3.c ed25519_donna/ed25519_keccak.c +SRCS += monero/base58.c +SRCS += monero/serialize.c +SRCS += monero/xmr.c +SRCS += blake256.c +SRCS += blake2b.c blake2s.c +SRCS += chacha_drbg.c +SRCS += groestl.c +SRCS += chacha20poly1305/chacha20poly1305.c chacha20poly1305/chacha_merged.c chacha20poly1305/poly1305_donna.c chacha20poly1305/rfc7539.c +SRCS += rc4.c +SRCS += nem.c +SRCS += segwit_addr.c cash_addr.c +SRCS += memzero.c +SRCS += shamir.c +SRCS += hmac_drbg.c +SRCS += rfc6979.c +SRCS += slip39.c +SRCS += zkp_context.c +SRCS += zkp_ecdsa.c +SRCS += zkp_bip340.c +SRCS += cardano.c + +OBJS = $(SRCS:.c=.o) +OBJS += secp256k1-zkp.o +OBJS += precomputed_ecmult.o +OBJS += precomputed_ecmult_gen.o + +TESTLIBS = $(shell pkg-config --libs check) -lpthread -lm +TESTSSLLIBS = $(shell pkg-config --libs openssl) + +all: tools tests + +%.o: %.c %.h options.h + $(CC) $(CFLAGS) -o $@ -c $< + +tests: tests/test_check tests/test_openssl tests/test_speed tests/libtrezor-crypto.so tests/aestst + +tests/aestst: aes/aestst.o aes/aescrypt.o aes/aeskey.o aes/aestab.o + $(CC) $(CFLAGS) $^ -o $@ + +tests/test_check.o: tests/test_check_cardano.h tests/test_check_monero.h tests/test_check_cashaddr.h tests/test_check_segwit.h + +tests/test_check: tests/test_check.o $(OBJS) + $(CC) $(CFLAGS) tests/test_check.o $(OBJS) $(TESTLIBS) -o tests/test_check + +tests/test_speed: tests/test_speed.o $(OBJS) + $(CC) $(CFLAGS) tests/test_speed.o $(OBJS) -o tests/test_speed + +tests/test_openssl: tests/test_openssl.o $(OBJS) + $(CC) $(CFLAGS) tests/test_openssl.o $(OBJS) $(TESTSSLLIBS) -o tests/test_openssl + +tests/libtrezor-crypto.so: $(SRCS) secp256k1-zkp.o precomputed_ecmult.o precomputed_ecmult_gen.o + $(CC) $(CFLAGS) -DAES_128 -DAES_192 -fPIC -shared $(SRCS) secp256k1-zkp.o precomputed_ecmult.o precomputed_ecmult_gen.o -o tests/libtrezor-crypto.so + +tools: tools/xpubaddrgen tools/mktable tools/bip39bruteforce + +tools/xpubaddrgen: tools/xpubaddrgen.o $(OBJS) + $(CC) $(CFLAGS) tools/xpubaddrgen.o $(OBJS) -o tools/xpubaddrgen + +tools/mktable: tools/mktable.o $(OBJS) + $(CC) $(CFLAGS) tools/mktable.o $(OBJS) -o tools/mktable + +tools/bip39bruteforce: tools/bip39bruteforce.o $(OBJS) + $(CC) $(CFLAGS) tools/bip39bruteforce.o $(OBJS) -o tools/bip39bruteforce + +fuzzer: fuzzer/fuzzer.o $(OBJS) + $(CC) $(CFLAGS) fuzzer/fuzzer.o $(OBJS) -o fuzzer/fuzzer + +precomputed_ecmult.o: + $(CC) $(CFLAGS) -Wno-unused-function $(ZKP_CFLAGS) -fPIC -c $(ZKP_PATH)/src/precomputed_ecmult.c -o precomputed_ecmult.o + +precomputed_ecmult_gen.o: + $(CC) $(CFLAGS) -Wno-unused-function $(ZKP_CFLAGS) -fPIC -c $(ZKP_PATH)/src/precomputed_ecmult_gen.c -o precomputed_ecmult_gen.o + +secp256k1-zkp.o: + $(CC) $(CFLAGS) -Wno-unused-function $(ZKP_CFLAGS) -fPIC -I$(ZKP_PATH) -I$(ZKP_PATH)/src -c $(ZKP_PATH)/src/secp256k1.c -o secp256k1-zkp.o + +clean: + rm -f *.o aes/*.o chacha20poly1305/*.o ed25519_donna/*.o monero/*.o + rm -f tests/*.o tests/test_check tests/test_speed tests/test_openssl tests/libtrezor-crypto.so tests/aestst + rm -f tools/*.o tools/xpubaddrgen tools/mktable tools/bip39bruteforce + rm -f fuzzer/*.o fuzzer/fuzzer + rm -f secp256k1-zkp.o precomputed_ecmult.o precomputed_ecmult_gen.o + +clean-fuzzer: clean + rm -f crash-* fuzz-*.log slow-unit-* timeout-* diff --git a/applications/external/flipbip/lib/crypto/address.c b/applications/external/flipbip/lib/crypto/address.c new file mode 100644 index 000000000..2e791d05f --- /dev/null +++ b/applications/external/flipbip/lib/crypto/address.c @@ -0,0 +1,90 @@ +/** + * Copyright (c) 2016 Daira Hopwood + * Copyright (c) 2016 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "address.h" +#include "bignum.h" + +size_t address_prefix_bytes_len(uint32_t address_type) { + if(address_type <= 0xFF) return 1; + if(address_type <= 0xFFFF) return 2; + if(address_type <= 0xFFFFFF) return 3; + return 4; +} + +void address_write_prefix_bytes(uint32_t address_type, uint8_t* out) { + if(address_type > 0xFFFFFF) *(out++) = address_type >> 24; + if(address_type > 0xFFFF) *(out++) = (address_type >> 16) & 0xFF; + if(address_type > 0xFF) *(out++) = (address_type >> 8) & 0xFF; + *(out++) = address_type & 0xFF; +} + +bool address_check_prefix(const uint8_t* addr, uint32_t address_type) { + if(address_type <= 0xFF) { + return address_type == (uint32_t)(addr[0]); + } + if(address_type <= 0xFFFF) { + return address_type == (((uint32_t)addr[0] << 8) | ((uint32_t)addr[1])); + } + if(address_type <= 0xFFFFFF) { + return address_type == + (((uint32_t)addr[0] << 16) | ((uint32_t)addr[1] << 8) | ((uint32_t)addr[2])); + } + return address_type == (((uint32_t)addr[0] << 24) | ((uint32_t)addr[1] << 16) | + ((uint32_t)addr[2] << 8) | ((uint32_t)addr[3])); +} + +#if USE_ETHEREUM +#include "sha3.h" + +void ethereum_address_checksum(const uint8_t* addr, char* address, bool rskip60, uint64_t chain_id) { + const char* hex = "0123456789abcdef"; + address[0] = '0'; + address[1] = 'x'; + for(int i = 0; i < 20; i++) { + address[2 + i * 2] = hex[(addr[i] >> 4) & 0xF]; + address[2 + i * 2 + 1] = hex[addr[i] & 0xF]; + } + address[42] = 0; + + SHA3_CTX ctx = {0}; + uint8_t hash[32] = {0}; + keccak_256_Init(&ctx); + if(rskip60) { + char prefix[16] = {0}; + int prefix_size = + bn_format_uint64(chain_id, NULL, "0x", 0, 0, false, 0, prefix, sizeof(prefix)); + keccak_Update(&ctx, (const uint8_t*)prefix, prefix_size); + } + keccak_Update(&ctx, (const uint8_t*)(address + 2), 40); + keccak_Final(&ctx, hash); + + for(int i = 0; i < 20; i++) { + if((hash[i] & 0x80) && address[2 + i * 2] >= 'a' && address[2 + i * 2] <= 'f') { + address[2 + i * 2] -= 0x20; + } + if((hash[i] & 0x08) && address[2 + i * 2 + 1] >= 'a' && address[2 + i * 2 + 1] <= 'f') { + address[2 + i * 2 + 1] -= 0x20; + } + } +} +#endif diff --git a/applications/external/flipbip/lib/crypto/address.h b/applications/external/flipbip/lib/crypto/address.h new file mode 100644 index 000000000..e2767d6b0 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/address.h @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2016 Daira Hopwood + * Copyright (c) 2016 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __ADDRESS_H__ +#define __ADDRESS_H__ + +#include +#include +#include +#include "options.h" + +size_t address_prefix_bytes_len(uint32_t address_type); +void address_write_prefix_bytes(uint32_t address_type, uint8_t* out); +bool address_check_prefix(const uint8_t* addr, uint32_t address_type); +#if USE_ETHEREUM +void ethereum_address_checksum(const uint8_t* addr, char* address, bool rskip60, uint64_t chain_id); +#endif + +#endif diff --git a/applications/external/flipbip/lib/crypto/aes/aes.h b/applications/external/flipbip/lib/crypto/aes/aes.h new file mode 100644 index 000000000..b277c390d --- /dev/null +++ b/applications/external/flipbip/lib/crypto/aes/aes.h @@ -0,0 +1,256 @@ +/* +--------------------------------------------------------------------------- +Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. + +The redistribution and use of this software (with or without changes) +is allowed without the payment of fees or royalties provided that: + + source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation. + +This software is provided 'as is' with no explicit or implied warranties +in respect of its operation, including, but not limited to, correctness +and fitness for purpose. +--------------------------------------------------------------------------- +Issue Date: 02/08/2018 + + This file contains the definitions required to use AES in C. See aesopt.h + for optimisation details. +*/ + +#ifndef _AES_H +#define _AES_H + +#include +#include + +#define VOID_RETURN void +#define INT_RETURN int +#define ALIGN_OFFSET(x, n) (((intptr_t)(x)) & ((n)-1)) +#define ALIGN_FLOOR(x, n) ((uint8_t*)(x) - (((intptr_t)(x)) & ((n)-1))) +#define ALIGN_CEIL(x, n) ((uint8_t*)(x) + (-((intptr_t)(x)) & ((n)-1))) + +#if defined(__cplusplus) +extern "C" { +#endif + +// #define AES_128 /* if a fast 128 bit key scheduler is needed */ +// #define AES_192 /* if a fast 192 bit key scheduler is needed */ +#define AES_256 /* if a fast 256 bit key scheduler is needed */ +// #define AES_VAR /* if variable key size scheduler is needed */ +#if 1 +#define AES_MODES /* if support is needed for modes in the C code */ +#endif /* (these will use AES_NI if it is present) */ +#if 0 /* add this to make direct calls to the AES_NI */ +#/* implemented CBC and CTR modes available */ +#define ADD_AESNI_MODE_CALLS +#endif + +/* The following must also be set in assembler files if being used */ + +#define AES_ENCRYPT /* if support for encryption is needed */ +#define AES_DECRYPT /* if support for decryption is needed */ + +#define AES_BLOCK_SIZE_P2 4 /* AES block size as a power of 2 */ +#define AES_BLOCK_SIZE (1 << AES_BLOCK_SIZE_P2) /* AES block size */ +#define N_COLS 4 /* the number of columns in the state */ + +/* The key schedule length is 11, 13 or 15 16-byte blocks for 128, */ +/* 192 or 256-bit keys respectively. That is 176, 208 or 240 bytes */ +/* or 44, 52 or 60 32-bit words. */ + +#if defined(AES_VAR) || defined(AES_256) +#define KS_LENGTH 60 +#elif defined(AES_192) +#define KS_LENGTH 52 +#else +#define KS_LENGTH 44 +#endif + +#define AES_RETURN INT_RETURN + +/* the character array 'inf' in the following structures is used */ +/* to hold AES context information. This AES code uses cx->inf.b[0] */ +/* to hold the number of rounds multiplied by 16. The other three */ +/* elements can be used by code that implements additional modes */ + +typedef union { + uint32_t l; + uint8_t b[4]; +} aes_inf; + +#ifdef _MSC_VER +#pragma warning(disable : 4324) +#endif + +#if defined(_MSC_VER) && defined(_WIN64) +#define ALIGNED_(x) __declspec(align(x)) +#elif defined(__GNUC__) && defined(__x86_64__) +#define ALIGNED_(x) __attribute__((aligned(x))) +#else +#define ALIGNED_(x) +#endif + +typedef struct ALIGNED_(16) { + uint32_t ks[KS_LENGTH]; + aes_inf inf; +} aes_encrypt_ctx; + +typedef struct ALIGNED_(16) { + uint32_t ks[KS_LENGTH]; + aes_inf inf; +} aes_decrypt_ctx; + +#ifdef _MSC_VER +#pragma warning(default : 4324) +#endif + +/* This routine must be called before first use if non-static */ +/* tables are being used */ + +AES_RETURN aes_init(void); + +/* Key lengths in the range 16 <= key_len <= 32 are given in bytes, */ +/* those in the range 128 <= key_len <= 256 are given in bits */ + +#if defined(AES_ENCRYPT) + +#if defined(AES_128) || defined(AES_VAR) +AES_RETURN aes_encrypt_key128(const unsigned char* key, aes_encrypt_ctx cx[1]); +#endif + +#if defined(AES_192) || defined(AES_VAR) +AES_RETURN aes_encrypt_key192(const unsigned char* key, aes_encrypt_ctx cx[1]); +#endif + +#if defined(AES_256) || defined(AES_VAR) +AES_RETURN aes_encrypt_key256(const unsigned char* key, aes_encrypt_ctx cx[1]); +#endif + +#if defined(AES_VAR) +AES_RETURN aes_encrypt_key(const unsigned char* key, int key_len, aes_encrypt_ctx cx[1]); +#endif + +AES_RETURN aes_encrypt(const unsigned char* in, unsigned char* out, const aes_encrypt_ctx cx[1]); + +#endif + +#if defined(AES_DECRYPT) + +#if defined(AES_128) || defined(AES_VAR) +AES_RETURN aes_decrypt_key128(const unsigned char* key, aes_decrypt_ctx cx[1]); +#endif + +#if defined(AES_192) || defined(AES_VAR) +AES_RETURN aes_decrypt_key192(const unsigned char* key, aes_decrypt_ctx cx[1]); +#endif + +#if defined(AES_256) || defined(AES_VAR) +AES_RETURN aes_decrypt_key256(const unsigned char* key, aes_decrypt_ctx cx[1]); +#endif + +#if defined(AES_VAR) +AES_RETURN aes_decrypt_key(const unsigned char* key, int key_len, aes_decrypt_ctx cx[1]); +#endif + +AES_RETURN aes_decrypt(const unsigned char* in, unsigned char* out, const aes_decrypt_ctx cx[1]); + +#endif + +#if defined(AES_MODES) + +/* Multiple calls to the following subroutines for multiple block */ +/* ECB, CBC, CFB, OFB and CTR mode encryption can be used to handle */ +/* long messages incrementally provided that the context AND the iv */ +/* are preserved between all such calls. For the ECB and CBC modes */ +/* each individual call within a series of incremental calls must */ +/* process only full blocks (i.e. len must be a multiple of 16) but */ +/* the CFB, OFB and CTR mode calls can handle multiple incremental */ +/* calls of any length. Each mode is reset when a new AES key is */ +/* set but ECB needs no reset and CBC can be reset without setting */ +/* a new key by setting a new IV value. To reset CFB, OFB and CTR */ +/* without setting the key, aes_mode_reset() must be called and the */ +/* IV must be set. NOTE: All these calls update the IV on exit so */ +/* this has to be reset if a new operation with the same IV as the */ +/* previous one is required (or decryption follows encryption with */ +/* the same IV array). */ + +AES_RETURN aes_test_alignment_detection(unsigned int n); + +AES_RETURN aes_ecb_encrypt( + const unsigned char* ibuf, + unsigned char* obuf, + int len, + const aes_encrypt_ctx cx[1]); + +AES_RETURN aes_ecb_decrypt( + const unsigned char* ibuf, + unsigned char* obuf, + int len, + const aes_decrypt_ctx cx[1]); + +AES_RETURN aes_cbc_encrypt( + const unsigned char* ibuf, + unsigned char* obuf, + int len, + unsigned char* iv, + const aes_encrypt_ctx cx[1]); + +AES_RETURN aes_cbc_decrypt( + const unsigned char* ibuf, + unsigned char* obuf, + int len, + unsigned char* iv, + const aes_decrypt_ctx cx[1]); + +AES_RETURN aes_mode_reset(aes_encrypt_ctx cx[1]); + +AES_RETURN aes_cfb_encrypt( + const unsigned char* ibuf, + unsigned char* obuf, + int len, + unsigned char* iv, + aes_encrypt_ctx cx[1]); + +AES_RETURN aes_cfb_decrypt( + const unsigned char* ibuf, + unsigned char* obuf, + int len, + unsigned char* iv, + aes_encrypt_ctx cx[1]); + +#define aes_ofb_encrypt aes_ofb_crypt +#define aes_ofb_decrypt aes_ofb_crypt + +AES_RETURN aes_ofb_crypt( + const unsigned char* ibuf, + unsigned char* obuf, + int len, + unsigned char* iv, + aes_encrypt_ctx cx[1]); + +typedef void cbuf_inc(unsigned char* cbuf); + +#define aes_ctr_encrypt aes_ctr_crypt +#define aes_ctr_decrypt aes_ctr_crypt + +AES_RETURN aes_ctr_crypt( + const unsigned char* ibuf, + unsigned char* obuf, + int len, + unsigned char* cbuf, + cbuf_inc ctr_inc, + aes_encrypt_ctx cx[1]); + +void aes_ctr_cbuf_inc(unsigned char* cbuf); + +#endif + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/applications/external/flipbip/lib/crypto/aes/aes_modes.c b/applications/external/flipbip/lib/crypto/aes/aes_modes.c new file mode 100644 index 000000000..7e6b7eb34 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/aes/aes_modes.c @@ -0,0 +1,932 @@ +/* +--------------------------------------------------------------------------- +Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. + +The redistribution and use of this software (with or without changes) +is allowed without the payment of fees or royalties provided that: + + source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation. + +This software is provided 'as is' with no explicit or implied warranties +in respect of its operation, including, but not limited to, correctness +and fitness for purpose. +--------------------------------------------------------------------------- +Issue Date: 20/12/2007 + + These subroutines implement multiple block AES modes for ECB, CBC, CFB, + OFB and CTR encryption, The code provides support for the VIA Advanced + Cryptography Engine (ACE). + + NOTE: In the following subroutines, the AES contexts (ctx) must be + 16 byte aligned if VIA ACE is being used +*/ + +#include +#include +#include + +#include "aesopt.h" + +#if defined(AES_MODES) +#if defined(__cplusplus) +extern "C" { +#endif + +#if defined(_MSC_VER) && (_MSC_VER > 800) +#pragma intrinsic(memcpy) +#endif + +#define BFR_BLOCKS 8 + +/* These values are used to detect long word alignment in order to */ +/* speed up some buffer operations. This facility may not work on */ +/* some machines so this define can be commented out if necessary */ + +#define FAST_BUFFER_OPERATIONS + +#define lp32(x) ((uint32_t*)(x)) + +#if defined(USE_VIA_ACE_IF_PRESENT) + +#include "aes_via_ace.h" + +#pragma pack(16) + +aligned_array(unsigned long, enc_gen_table, 12, 16) = NEH_ENC_GEN_DATA; +aligned_array(unsigned long, enc_load_table, 12, 16) = NEH_ENC_LOAD_DATA; +aligned_array(unsigned long, enc_hybrid_table, 12, 16) = NEH_ENC_HYBRID_DATA; +aligned_array(unsigned long, dec_gen_table, 12, 16) = NEH_DEC_GEN_DATA; +aligned_array(unsigned long, dec_load_table, 12, 16) = NEH_DEC_LOAD_DATA; +aligned_array(unsigned long, dec_hybrid_table, 12, 16) = NEH_DEC_HYBRID_DATA; + +/* NOTE: These control word macros must only be used after */ +/* a key has been set up because they depend on key size */ +/* See the VIA ACE documentation for key type information */ +/* and aes_via_ace.h for non-default NEH_KEY_TYPE values */ + +#ifndef NEH_KEY_TYPE +#define NEH_KEY_TYPE NEH_HYBRID +#endif + +#if NEH_KEY_TYPE == NEH_LOAD +#define kd_adr(c) ((uint8_t*)(c)->ks) +#elif NEH_KEY_TYPE == NEH_GENERATE +#define kd_adr(c) ((uint8_t*)(c)->ks + (c)->inf.b[0]) +#elif NEH_KEY_TYPE == NEH_HYBRID +#define kd_adr(c) ((uint8_t*)(c)->ks + ((c)->inf.b[0] == 160 ? 160 : 0)) +#else +#error no key type defined for VIA ACE +#endif + +#else + +#define aligned_array(type, name, no, stride) type name[no] +#define aligned_auto(type, name, no, stride) type name[no] + +#endif + +#if defined(_MSC_VER) && _MSC_VER > 1200 + +#define via_cwd(cwd, ty, dir, len) unsigned long* cwd = (dir##_##ty##_table + ((len - 128) >> 4)) + +#else + +#define via_cwd(cwd, ty, dir, len) \ + aligned_auto(unsigned long, cwd, 4, 16); \ + cwd[1] = cwd[2] = cwd[3] = 0; \ + cwd[0] = neh_##dir##_##ty##_key(len) + +#endif + +/* test the code for detecting and setting pointer alignment */ + +AES_RETURN aes_test_alignment_detection(unsigned int n) /* 4 <= n <= 16 */ +{ + uint8_t p[16]; + uint32_t i = 0, count_eq = 0, count_neq = 0; + + if(n < 4 || n > 16) return EXIT_FAILURE; + + for(i = 0; i < n; ++i) { + uint8_t *qf = ALIGN_FLOOR(p + i, n), *qh = ALIGN_CEIL(p + i, n); + + if(qh == qf) + ++count_eq; + else if(qh == qf + n) + ++count_neq; + else + return EXIT_FAILURE; + } + return (count_eq != 1 || count_neq != n - 1 ? EXIT_FAILURE : EXIT_SUCCESS); +} + +AES_RETURN aes_mode_reset(aes_encrypt_ctx ctx[1]) { + ctx->inf.b[2] = 0; + return EXIT_SUCCESS; +} + +AES_RETURN aes_ecb_encrypt( + const unsigned char* ibuf, + unsigned char* obuf, + int len, + const aes_encrypt_ctx ctx[1]) { + int nb = len >> AES_BLOCK_SIZE_P2; + + if(len & (AES_BLOCK_SIZE - 1)) return EXIT_FAILURE; + +#if defined(USE_VIA_ACE_IF_PRESENT) + + if(ctx->inf.b[1] == 0xff) { + uint8_t* ksp = (uint8_t*)(ctx->ks); + via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192); + + if(ALIGN_OFFSET(ctx, 16)) return EXIT_FAILURE; + + if(!ALIGN_OFFSET(ibuf, 16) && !ALIGN_OFFSET(obuf, 16)) { + via_ecb_op5(ksp, cwd, ibuf, obuf, nb); + } else { + aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); + uint8_t *ip = NULL, *op = NULL; + + while(nb) { + int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb); + + ip = (ALIGN_OFFSET(ibuf, 16) ? buf : ibuf); + op = (ALIGN_OFFSET(obuf, 16) ? buf : obuf); + + if(ip != ibuf) memcpy(buf, ibuf, m * AES_BLOCK_SIZE); + + via_ecb_op5(ksp, cwd, ip, op, m); + + if(op != obuf) memcpy(obuf, buf, m * AES_BLOCK_SIZE); + + ibuf += m * AES_BLOCK_SIZE; + obuf += m * AES_BLOCK_SIZE; + nb -= m; + } + } + + return EXIT_SUCCESS; + } + +#endif + +#if !defined(ASSUME_VIA_ACE_PRESENT) + while(nb--) { + if(aes_encrypt(ibuf, obuf, ctx) != EXIT_SUCCESS) return EXIT_FAILURE; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + } +#endif + return EXIT_SUCCESS; +} + +AES_RETURN aes_ecb_decrypt( + const unsigned char* ibuf, + unsigned char* obuf, + int len, + const aes_decrypt_ctx ctx[1]) { + int nb = len >> AES_BLOCK_SIZE_P2; + + if(len & (AES_BLOCK_SIZE - 1)) return EXIT_FAILURE; + +#if defined(USE_VIA_ACE_IF_PRESENT) + + if(ctx->inf.b[1] == 0xff) { + uint8_t* ksp = kd_adr(ctx); + via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192); + + if(ALIGN_OFFSET(ctx, 16)) return EXIT_FAILURE; + + if(!ALIGN_OFFSET(ibuf, 16) && !ALIGN_OFFSET(obuf, 16)) { + via_ecb_op5(ksp, cwd, ibuf, obuf, nb); + } else { + aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); + uint8_t *ip = NULL, *op = NULL; + + while(nb) { + int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb); + + ip = (ALIGN_OFFSET(ibuf, 16) ? buf : ibuf); + op = (ALIGN_OFFSET(obuf, 16) ? buf : obuf); + + if(ip != ibuf) memcpy(buf, ibuf, m * AES_BLOCK_SIZE); + + via_ecb_op5(ksp, cwd, ip, op, m); + + if(op != obuf) memcpy(obuf, buf, m * AES_BLOCK_SIZE); + + ibuf += m * AES_BLOCK_SIZE; + obuf += m * AES_BLOCK_SIZE; + nb -= m; + } + } + + return EXIT_SUCCESS; + } + +#endif + +#if !defined(ASSUME_VIA_ACE_PRESENT) + while(nb--) { + if(aes_decrypt(ibuf, obuf, ctx) != EXIT_SUCCESS) return EXIT_FAILURE; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + } +#endif + return EXIT_SUCCESS; +} + +AES_RETURN aes_cbc_encrypt( + const unsigned char* ibuf, + unsigned char* obuf, + int len, + unsigned char* iv, + const aes_encrypt_ctx ctx[1]) { + int nb = len >> AES_BLOCK_SIZE_P2; + + if(len & (AES_BLOCK_SIZE - 1)) return EXIT_FAILURE; + +#if defined(USE_VIA_ACE_IF_PRESENT) + + if(ctx->inf.b[1] == 0xff) { + uint8_t *ksp = (uint8_t*)(ctx->ks), *ivp = iv; + aligned_auto(uint8_t, liv, AES_BLOCK_SIZE, 16); + via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192); + + if(ALIGN_OFFSET(ctx, 16)) return EXIT_FAILURE; + + if(ALIGN_OFFSET(iv, 16)) /* ensure an aligned iv */ + { + ivp = liv; + memcpy(liv, iv, AES_BLOCK_SIZE); + } + + if(!ALIGN_OFFSET(ibuf, 16) && !ALIGN_OFFSET(obuf, 16) && !ALIGN_OFFSET(iv, 16)) { + via_cbc_op7(ksp, cwd, ibuf, obuf, nb, ivp, ivp); + } else { + aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); + uint8_t *ip = NULL, *op = NULL; + + while(nb) { + int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb); + + ip = (ALIGN_OFFSET(ibuf, 16) ? buf : ibuf); + op = (ALIGN_OFFSET(obuf, 16) ? buf : obuf); + + if(ip != ibuf) memcpy(buf, ibuf, m * AES_BLOCK_SIZE); + + via_cbc_op7(ksp, cwd, ip, op, m, ivp, ivp); + + if(op != obuf) memcpy(obuf, buf, m * AES_BLOCK_SIZE); + + ibuf += m * AES_BLOCK_SIZE; + obuf += m * AES_BLOCK_SIZE; + nb -= m; + } + } + + if(iv != ivp) memcpy(iv, ivp, AES_BLOCK_SIZE); + + return EXIT_SUCCESS; + } + +#endif + +#if !defined(ASSUME_VIA_ACE_PRESENT) +#ifdef FAST_BUFFER_OPERATIONS + if(!ALIGN_OFFSET(ibuf, 4) && !ALIGN_OFFSET(iv, 4)) + while(nb--) { + lp32(iv)[0] ^= lp32(ibuf)[0]; + lp32(iv)[1] ^= lp32(ibuf)[1]; + lp32(iv)[2] ^= lp32(ibuf)[2]; + lp32(iv)[3] ^= lp32(ibuf)[3]; + if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE; + memcpy(obuf, iv, AES_BLOCK_SIZE); + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + } + else +#endif + while(nb--) { + iv[0] ^= ibuf[0]; + iv[1] ^= ibuf[1]; + iv[2] ^= ibuf[2]; + iv[3] ^= ibuf[3]; + iv[4] ^= ibuf[4]; + iv[5] ^= ibuf[5]; + iv[6] ^= ibuf[6]; + iv[7] ^= ibuf[7]; + iv[8] ^= ibuf[8]; + iv[9] ^= ibuf[9]; + iv[10] ^= ibuf[10]; + iv[11] ^= ibuf[11]; + iv[12] ^= ibuf[12]; + iv[13] ^= ibuf[13]; + iv[14] ^= ibuf[14]; + iv[15] ^= ibuf[15]; + if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE; + memcpy(obuf, iv, AES_BLOCK_SIZE); + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + } +#endif + return EXIT_SUCCESS; +} + +AES_RETURN aes_cbc_decrypt( + const unsigned char* ibuf, + unsigned char* obuf, + int len, + unsigned char* iv, + const aes_decrypt_ctx ctx[1]) { + unsigned char tmp[AES_BLOCK_SIZE]; + int nb = len >> AES_BLOCK_SIZE_P2; + + if(len & (AES_BLOCK_SIZE - 1)) return EXIT_FAILURE; + +#if defined(USE_VIA_ACE_IF_PRESENT) + + if(ctx->inf.b[1] == 0xff) { + uint8_t *ksp = kd_adr(ctx), *ivp = iv; + aligned_auto(uint8_t, liv, AES_BLOCK_SIZE, 16); + via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192); + + if(ALIGN_OFFSET(ctx, 16)) return EXIT_FAILURE; + + if(ALIGN_OFFSET(iv, 16)) /* ensure an aligned iv */ + { + ivp = liv; + memcpy(liv, iv, AES_BLOCK_SIZE); + } + + if(!ALIGN_OFFSET(ibuf, 16) && !ALIGN_OFFSET(obuf, 16) && !ALIGN_OFFSET(iv, 16)) { + via_cbc_op6(ksp, cwd, ibuf, obuf, nb, ivp); + } else { + aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); + uint8_t *ip = NULL, *op = NULL; + + while(nb) { + int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb); + + ip = (ALIGN_OFFSET(ibuf, 16) ? buf : ibuf); + op = (ALIGN_OFFSET(obuf, 16) ? buf : obuf); + + if(ip != ibuf) memcpy(buf, ibuf, m * AES_BLOCK_SIZE); + + via_cbc_op6(ksp, cwd, ip, op, m, ivp); + + if(op != obuf) memcpy(obuf, buf, m * AES_BLOCK_SIZE); + + ibuf += m * AES_BLOCK_SIZE; + obuf += m * AES_BLOCK_SIZE; + nb -= m; + } + } + + if(iv != ivp) memcpy(iv, ivp, AES_BLOCK_SIZE); + + return EXIT_SUCCESS; + } +#endif + +#if !defined(ASSUME_VIA_ACE_PRESENT) +#ifdef FAST_BUFFER_OPERATIONS + if(!ALIGN_OFFSET(obuf, 4) && !ALIGN_OFFSET(iv, 4)) + while(nb--) { + memcpy(tmp, ibuf, AES_BLOCK_SIZE); + if(aes_decrypt(ibuf, obuf, ctx) != EXIT_SUCCESS) return EXIT_FAILURE; + lp32(obuf)[0] ^= lp32(iv)[0]; + lp32(obuf)[1] ^= lp32(iv)[1]; + lp32(obuf)[2] ^= lp32(iv)[2]; + lp32(obuf)[3] ^= lp32(iv)[3]; + memcpy(iv, tmp, AES_BLOCK_SIZE); + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + } + else +#endif + while(nb--) { + memcpy(tmp, ibuf, AES_BLOCK_SIZE); + if(aes_decrypt(ibuf, obuf, ctx) != EXIT_SUCCESS) return EXIT_FAILURE; + obuf[0] ^= iv[0]; + obuf[1] ^= iv[1]; + obuf[2] ^= iv[2]; + obuf[3] ^= iv[3]; + obuf[4] ^= iv[4]; + obuf[5] ^= iv[5]; + obuf[6] ^= iv[6]; + obuf[7] ^= iv[7]; + obuf[8] ^= iv[8]; + obuf[9] ^= iv[9]; + obuf[10] ^= iv[10]; + obuf[11] ^= iv[11]; + obuf[12] ^= iv[12]; + obuf[13] ^= iv[13]; + obuf[14] ^= iv[14]; + obuf[15] ^= iv[15]; + memcpy(iv, tmp, AES_BLOCK_SIZE); + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + } +#endif + return EXIT_SUCCESS; +} + +AES_RETURN aes_cfb_encrypt( + const unsigned char* ibuf, + unsigned char* obuf, + int len, + unsigned char* iv, + aes_encrypt_ctx ctx[1]) { + int cnt = 0, b_pos = (int)ctx->inf.b[2], nb; + + if(b_pos) /* complete any partial block */ + { + while(b_pos < AES_BLOCK_SIZE && cnt < len) { + *obuf++ = (iv[b_pos++] ^= *ibuf++); + cnt++; + } + + b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); + } + + if((nb = (len - cnt) >> AES_BLOCK_SIZE_P2) != 0) /* process whole blocks */ + { +#if defined(USE_VIA_ACE_IF_PRESENT) + + if(ctx->inf.b[1] == 0xff) { + int m; + uint8_t *ksp = (uint8_t*)(ctx->ks), *ivp = iv; + aligned_auto(uint8_t, liv, AES_BLOCK_SIZE, 16); + via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192); + + if(ALIGN_OFFSET(ctx, 16)) return EXIT_FAILURE; + + if(ALIGN_OFFSET(iv, 16)) /* ensure an aligned iv */ + { + ivp = liv; + memcpy(liv, iv, AES_BLOCK_SIZE); + } + + if(!ALIGN_OFFSET(ibuf, 16) && !ALIGN_OFFSET(obuf, 16)) { + via_cfb_op7(ksp, cwd, ibuf, obuf, nb, ivp, ivp); + ibuf += nb * AES_BLOCK_SIZE; + obuf += nb * AES_BLOCK_SIZE; + cnt += nb * AES_BLOCK_SIZE; + } else /* input, output or both are unaligned */ + { + aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); + uint8_t *ip = NULL, *op = NULL; + + while(nb) { + m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m; + + ip = (ALIGN_OFFSET(ibuf, 16) ? buf : ibuf); + op = (ALIGN_OFFSET(obuf, 16) ? buf : obuf); + + if(ip != ibuf) memcpy(buf, ibuf, m * AES_BLOCK_SIZE); + + via_cfb_op7(ksp, cwd, ip, op, m, ivp, ivp); + + if(op != obuf) memcpy(obuf, buf, m * AES_BLOCK_SIZE); + + ibuf += m * AES_BLOCK_SIZE; + obuf += m * AES_BLOCK_SIZE; + cnt += m * AES_BLOCK_SIZE; + } + } + + if(ivp != iv) memcpy(iv, ivp, AES_BLOCK_SIZE); + } +#else +#ifdef FAST_BUFFER_OPERATIONS + if(!ALIGN_OFFSET(ibuf, 4) && !ALIGN_OFFSET(obuf, 4) && !ALIGN_OFFSET(iv, 4)) + while(cnt + AES_BLOCK_SIZE <= len) { + assert(b_pos == 0); + if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE; + lp32(obuf)[0] = lp32(iv)[0] ^= lp32(ibuf)[0]; + lp32(obuf)[1] = lp32(iv)[1] ^= lp32(ibuf)[1]; + lp32(obuf)[2] = lp32(iv)[2] ^= lp32(ibuf)[2]; + lp32(obuf)[3] = lp32(iv)[3] ^= lp32(ibuf)[3]; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + cnt += AES_BLOCK_SIZE; + } + else +#endif + while(cnt + AES_BLOCK_SIZE <= len) { + assert(b_pos == 0); + if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE; + obuf[0] = iv[0] ^= ibuf[0]; + obuf[1] = iv[1] ^= ibuf[1]; + obuf[2] = iv[2] ^= ibuf[2]; + obuf[3] = iv[3] ^= ibuf[3]; + obuf[4] = iv[4] ^= ibuf[4]; + obuf[5] = iv[5] ^= ibuf[5]; + obuf[6] = iv[6] ^= ibuf[6]; + obuf[7] = iv[7] ^= ibuf[7]; + obuf[8] = iv[8] ^= ibuf[8]; + obuf[9] = iv[9] ^= ibuf[9]; + obuf[10] = iv[10] ^= ibuf[10]; + obuf[11] = iv[11] ^= ibuf[11]; + obuf[12] = iv[12] ^= ibuf[12]; + obuf[13] = iv[13] ^= ibuf[13]; + obuf[14] = iv[14] ^= ibuf[14]; + obuf[15] = iv[15] ^= ibuf[15]; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + cnt += AES_BLOCK_SIZE; + } +#endif + } + + while(cnt < len) { + if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE; + + while(cnt < len && b_pos < AES_BLOCK_SIZE) { + *obuf++ = (iv[b_pos++] ^= *ibuf++); + cnt++; + } + + b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); + } + + ctx->inf.b[2] = (uint8_t)b_pos; + return EXIT_SUCCESS; +} + +AES_RETURN aes_cfb_decrypt( + const unsigned char* ibuf, + unsigned char* obuf, + int len, + unsigned char* iv, + aes_encrypt_ctx ctx[1]) { + int cnt = 0, b_pos = (int)ctx->inf.b[2], nb; + + if(b_pos) /* complete any partial block */ + { + uint8_t t; + + while(b_pos < AES_BLOCK_SIZE && cnt < len) { + t = *ibuf++; + *obuf++ = t ^ iv[b_pos]; + iv[b_pos++] = t; + cnt++; + } + + b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); + } + + if((nb = (len - cnt) >> AES_BLOCK_SIZE_P2) != 0) /* process whole blocks */ + { +#if defined(USE_VIA_ACE_IF_PRESENT) + + if(ctx->inf.b[1] == 0xff) { + int m; + uint8_t *ksp = (uint8_t*)(ctx->ks), *ivp = iv; + aligned_auto(uint8_t, liv, AES_BLOCK_SIZE, 16); + via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192); + + if(ALIGN_OFFSET(ctx, 16)) return EXIT_FAILURE; + + if(ALIGN_OFFSET(iv, 16)) /* ensure an aligned iv */ + { + ivp = liv; + memcpy(liv, iv, AES_BLOCK_SIZE); + } + + if(!ALIGN_OFFSET(ibuf, 16) && !ALIGN_OFFSET(obuf, 16)) { + via_cfb_op6(ksp, cwd, ibuf, obuf, nb, ivp); + ibuf += nb * AES_BLOCK_SIZE; + obuf += nb * AES_BLOCK_SIZE; + cnt += nb * AES_BLOCK_SIZE; + } else /* input, output or both are unaligned */ + { + aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); + uint8_t *ip = NULL, *op = NULL; + + while(nb) { + m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m; + + ip = (ALIGN_OFFSET(ibuf, 16) ? buf : ibuf); + op = (ALIGN_OFFSET(obuf, 16) ? buf : obuf); + + if(ip != ibuf) /* input buffer is not aligned */ + memcpy(buf, ibuf, m * AES_BLOCK_SIZE); + + via_cfb_op6(ksp, cwd, ip, op, m, ivp); + + if(op != obuf) /* output buffer is not aligned */ + memcpy(obuf, buf, m * AES_BLOCK_SIZE); + + ibuf += m * AES_BLOCK_SIZE; + obuf += m * AES_BLOCK_SIZE; + cnt += m * AES_BLOCK_SIZE; + } + } + + if(ivp != iv) memcpy(iv, ivp, AES_BLOCK_SIZE); + } +#else +#ifdef FAST_BUFFER_OPERATIONS + if(!ALIGN_OFFSET(ibuf, 4) && !ALIGN_OFFSET(obuf, 4) && !ALIGN_OFFSET(iv, 4)) + while(cnt + AES_BLOCK_SIZE <= len) { + uint32_t t; + + assert(b_pos == 0); + if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE; + t = lp32(ibuf)[0], lp32(obuf)[0] = t ^ lp32(iv)[0], lp32(iv)[0] = t; + t = lp32(ibuf)[1], lp32(obuf)[1] = t ^ lp32(iv)[1], lp32(iv)[1] = t; + t = lp32(ibuf)[2], lp32(obuf)[2] = t ^ lp32(iv)[2], lp32(iv)[2] = t; + t = lp32(ibuf)[3], lp32(obuf)[3] = t ^ lp32(iv)[3], lp32(iv)[3] = t; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + cnt += AES_BLOCK_SIZE; + } + else +#endif + while(cnt + AES_BLOCK_SIZE <= len) { + uint8_t t; + + assert(b_pos == 0); + if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE; + t = ibuf[0], obuf[0] = t ^ iv[0], iv[0] = t; + t = ibuf[1], obuf[1] = t ^ iv[1], iv[1] = t; + t = ibuf[2], obuf[2] = t ^ iv[2], iv[2] = t; + t = ibuf[3], obuf[3] = t ^ iv[3], iv[3] = t; + t = ibuf[4], obuf[4] = t ^ iv[4], iv[4] = t; + t = ibuf[5], obuf[5] = t ^ iv[5], iv[5] = t; + t = ibuf[6], obuf[6] = t ^ iv[6], iv[6] = t; + t = ibuf[7], obuf[7] = t ^ iv[7], iv[7] = t; + t = ibuf[8], obuf[8] = t ^ iv[8], iv[8] = t; + t = ibuf[9], obuf[9] = t ^ iv[9], iv[9] = t; + t = ibuf[10], obuf[10] = t ^ iv[10], iv[10] = t; + t = ibuf[11], obuf[11] = t ^ iv[11], iv[11] = t; + t = ibuf[12], obuf[12] = t ^ iv[12], iv[12] = t; + t = ibuf[13], obuf[13] = t ^ iv[13], iv[13] = t; + t = ibuf[14], obuf[14] = t ^ iv[14], iv[14] = t; + t = ibuf[15], obuf[15] = t ^ iv[15], iv[15] = t; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + cnt += AES_BLOCK_SIZE; + } +#endif + } + + while(cnt < len) { + uint8_t t; + + if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE; + + while(cnt < len && b_pos < AES_BLOCK_SIZE) { + t = *ibuf++; + *obuf++ = t ^ iv[b_pos]; + iv[b_pos++] = t; + cnt++; + } + + b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); + } + + ctx->inf.b[2] = (uint8_t)b_pos; + return EXIT_SUCCESS; +} + +AES_RETURN aes_ofb_crypt( + const unsigned char* ibuf, + unsigned char* obuf, + int len, + unsigned char* iv, + aes_encrypt_ctx ctx[1]) { + int cnt = 0, b_pos = (int)ctx->inf.b[2], nb; + + if(b_pos) /* complete any partial block */ + { + while(b_pos < AES_BLOCK_SIZE && cnt < len) { + *obuf++ = iv[b_pos++] ^ *ibuf++; + cnt++; + } + + b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); + } + + if((nb = (len - cnt) >> AES_BLOCK_SIZE_P2) != 0) /* process whole blocks */ + { +#if defined(USE_VIA_ACE_IF_PRESENT) + + if(ctx->inf.b[1] == 0xff) { + int m; + uint8_t *ksp = (uint8_t*)(ctx->ks), *ivp = iv; + aligned_auto(uint8_t, liv, AES_BLOCK_SIZE, 16); + via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192); + + if(ALIGN_OFFSET(ctx, 16)) return EXIT_FAILURE; + + if(ALIGN_OFFSET(iv, 16)) /* ensure an aligned iv */ + { + ivp = liv; + memcpy(liv, iv, AES_BLOCK_SIZE); + } + + if(!ALIGN_OFFSET(ibuf, 16) && !ALIGN_OFFSET(obuf, 16)) { + via_ofb_op6(ksp, cwd, ibuf, obuf, nb, ivp); + ibuf += nb * AES_BLOCK_SIZE; + obuf += nb * AES_BLOCK_SIZE; + cnt += nb * AES_BLOCK_SIZE; + } else /* input, output or both are unaligned */ + { + aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); + uint8_t *ip = NULL, *op = NULL; + + while(nb) { + m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m; + + ip = (ALIGN_OFFSET(ibuf, 16) ? buf : ibuf); + op = (ALIGN_OFFSET(obuf, 16) ? buf : obuf); + + if(ip != ibuf) memcpy(buf, ibuf, m * AES_BLOCK_SIZE); + + via_ofb_op6(ksp, cwd, ip, op, m, ivp); + + if(op != obuf) memcpy(obuf, buf, m * AES_BLOCK_SIZE); + + ibuf += m * AES_BLOCK_SIZE; + obuf += m * AES_BLOCK_SIZE; + cnt += m * AES_BLOCK_SIZE; + } + } + + if(ivp != iv) memcpy(iv, ivp, AES_BLOCK_SIZE); + } +#else +#ifdef FAST_BUFFER_OPERATIONS + if(!ALIGN_OFFSET(ibuf, 4) && !ALIGN_OFFSET(obuf, 4) && !ALIGN_OFFSET(iv, 4)) + while(cnt + AES_BLOCK_SIZE <= len) { + assert(b_pos == 0); + if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE; + lp32(obuf)[0] = lp32(iv)[0] ^ lp32(ibuf)[0]; + lp32(obuf)[1] = lp32(iv)[1] ^ lp32(ibuf)[1]; + lp32(obuf)[2] = lp32(iv)[2] ^ lp32(ibuf)[2]; + lp32(obuf)[3] = lp32(iv)[3] ^ lp32(ibuf)[3]; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + cnt += AES_BLOCK_SIZE; + } + else +#endif + while(cnt + AES_BLOCK_SIZE <= len) { + assert(b_pos == 0); + if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE; + obuf[0] = iv[0] ^ ibuf[0]; + obuf[1] = iv[1] ^ ibuf[1]; + obuf[2] = iv[2] ^ ibuf[2]; + obuf[3] = iv[3] ^ ibuf[3]; + obuf[4] = iv[4] ^ ibuf[4]; + obuf[5] = iv[5] ^ ibuf[5]; + obuf[6] = iv[6] ^ ibuf[6]; + obuf[7] = iv[7] ^ ibuf[7]; + obuf[8] = iv[8] ^ ibuf[8]; + obuf[9] = iv[9] ^ ibuf[9]; + obuf[10] = iv[10] ^ ibuf[10]; + obuf[11] = iv[11] ^ ibuf[11]; + obuf[12] = iv[12] ^ ibuf[12]; + obuf[13] = iv[13] ^ ibuf[13]; + obuf[14] = iv[14] ^ ibuf[14]; + obuf[15] = iv[15] ^ ibuf[15]; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + cnt += AES_BLOCK_SIZE; + } +#endif + } + + while(cnt < len) { + if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE; + + while(cnt < len && b_pos < AES_BLOCK_SIZE) { + *obuf++ = iv[b_pos++] ^ *ibuf++; + cnt++; + } + + b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); + } + + ctx->inf.b[2] = (uint8_t)b_pos; + return EXIT_SUCCESS; +} + +#define BFR_LENGTH (BFR_BLOCKS * AES_BLOCK_SIZE) + +AES_RETURN aes_ctr_crypt( + const unsigned char* ibuf, + unsigned char* obuf, + int len, + unsigned char* cbuf, + cbuf_inc ctr_inc, + aes_encrypt_ctx ctx[1]) { + unsigned char* ip; + int i = 0, blen = 0, b_pos = (int)(ctx->inf.b[2]); + +#if defined(USE_VIA_ACE_IF_PRESENT) + aligned_auto(uint8_t, buf, BFR_LENGTH, 16); + if(ctx->inf.b[1] == 0xff && ALIGN_OFFSET(ctx, 16)) return EXIT_FAILURE; +#else + uint8_t buf[BFR_LENGTH] = {0}; +#endif + + if(b_pos) { + memcpy(buf, cbuf, AES_BLOCK_SIZE); + if(aes_ecb_encrypt(buf, buf, AES_BLOCK_SIZE, ctx) != EXIT_SUCCESS) return EXIT_FAILURE; + + while(b_pos < AES_BLOCK_SIZE && len) { + *obuf++ = *ibuf++ ^ buf[b_pos++]; + --len; + } + + if(len) ctr_inc(cbuf), b_pos = 0; + } + + while(len) { + blen = (len > BFR_LENGTH ? BFR_LENGTH : len), len -= blen; + + for(i = 0, ip = buf; i < (blen >> AES_BLOCK_SIZE_P2); ++i) { + memcpy(ip, cbuf, AES_BLOCK_SIZE); + ctr_inc(cbuf); + ip += AES_BLOCK_SIZE; + } + + if(blen & (AES_BLOCK_SIZE - 1)) memcpy(ip, cbuf, AES_BLOCK_SIZE), i++; + +#if defined(USE_VIA_ACE_IF_PRESENT) + if(ctx->inf.b[1] == 0xff) { + via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192); + via_ecb_op5((ctx->ks), cwd, buf, buf, i); + } else +#endif + if(aes_ecb_encrypt(buf, buf, i * AES_BLOCK_SIZE, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + + i = 0; + ip = buf; +#ifdef FAST_BUFFER_OPERATIONS + if(!ALIGN_OFFSET(ibuf, 4) && !ALIGN_OFFSET(obuf, 4) && !ALIGN_OFFSET(ip, 4)) + while(i + AES_BLOCK_SIZE <= blen) { + lp32(obuf)[0] = lp32(ibuf)[0] ^ lp32(ip)[0]; + lp32(obuf)[1] = lp32(ibuf)[1] ^ lp32(ip)[1]; + lp32(obuf)[2] = lp32(ibuf)[2] ^ lp32(ip)[2]; + lp32(obuf)[3] = lp32(ibuf)[3] ^ lp32(ip)[3]; + i += AES_BLOCK_SIZE; + ip += AES_BLOCK_SIZE; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + } + else +#endif + while(i + AES_BLOCK_SIZE <= blen) { + obuf[0] = ibuf[0] ^ ip[0]; + obuf[1] = ibuf[1] ^ ip[1]; + obuf[2] = ibuf[2] ^ ip[2]; + obuf[3] = ibuf[3] ^ ip[3]; + obuf[4] = ibuf[4] ^ ip[4]; + obuf[5] = ibuf[5] ^ ip[5]; + obuf[6] = ibuf[6] ^ ip[6]; + obuf[7] = ibuf[7] ^ ip[7]; + obuf[8] = ibuf[8] ^ ip[8]; + obuf[9] = ibuf[9] ^ ip[9]; + obuf[10] = ibuf[10] ^ ip[10]; + obuf[11] = ibuf[11] ^ ip[11]; + obuf[12] = ibuf[12] ^ ip[12]; + obuf[13] = ibuf[13] ^ ip[13]; + obuf[14] = ibuf[14] ^ ip[14]; + obuf[15] = ibuf[15] ^ ip[15]; + i += AES_BLOCK_SIZE; + ip += AES_BLOCK_SIZE; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + } + + while(i++ < blen) *obuf++ = *ibuf++ ^ ip[b_pos++]; + } + + ctx->inf.b[2] = (uint8_t)b_pos; + return EXIT_SUCCESS; +} + +void aes_ctr_cbuf_inc(unsigned char* cbuf) { + int i = AES_BLOCK_SIZE - 1; + while(i >= 0) { + cbuf[i]++; + if(cbuf[i]) return; // if there was no overflow + i--; + } +} + +#if defined(__cplusplus) +} +#endif +#endif diff --git a/applications/external/flipbip/lib/crypto/aes/aescrypt.c b/applications/external/flipbip/lib/crypto/aes/aescrypt.c new file mode 100644 index 000000000..a160b6f95 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/aes/aescrypt.c @@ -0,0 +1,349 @@ +/* +--------------------------------------------------------------------------- +Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. + +The redistribution and use of this software (with or without changes) +is allowed without the payment of fees or royalties provided that: + + source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation. + +This software is provided 'as is' with no explicit or implied warranties +in respect of its operation, including, but not limited to, correctness +and fitness for purpose. +--------------------------------------------------------------------------- +Issue Date: 20/12/2007 +*/ + +#include "aesopt.h" +#include "aestab.h" + +#if defined(USE_INTEL_AES_IF_PRESENT) +#include "aes_ni.h" +#else +/* map names here to provide the external API ('name' -> 'aes_name') */ +#define aes_xi(x) aes_##x +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +#define si(y, x, k, c) (s(y, c) = word_in(x, c) ^ (k)[c]) +#define so(y, x, c) word_out(y, c, s(x, c)) + +#if defined(ARRAYS) +#define locals(y, x) x[4], y[4] +#else +#define locals(y, x) x##0, x##1, x##2, x##3, y##0, y##1, y##2, y##3 +#endif + +#define l_copy(y, x) \ + s(y, 0) = s(x, 0); \ + s(y, 1) = s(x, 1); \ + s(y, 2) = s(x, 2); \ + s(y, 3) = s(x, 3); +#define state_in(y, x, k) \ + si(y, x, k, 0); \ + si(y, x, k, 1); \ + si(y, x, k, 2); \ + si(y, x, k, 3) +#define state_out(y, x) \ + so(y, x, 0); \ + so(y, x, 1); \ + so(y, x, 2); \ + so(y, x, 3) +#define round(rm, y, x, k) \ + rm(y, x, k, 0); \ + rm(y, x, k, 1); \ + rm(y, x, k, 2); \ + rm(y, x, k, 3) + +#if(FUNCS_IN_C & ENCRYPTION_IN_C) + +/* Visual C++ .Net v7.1 provides the fastest encryption code when using + Pentium optimiation with small code but this is poor for decryption + so we need to control this with the following VC++ pragmas +*/ + +#if defined(_MSC_VER) && !defined(_WIN64) && !defined(__clang__) +#pragma optimize("s", on) +#endif + +/* Given the column (c) of the output state variable, the following + macros give the input state variables which are needed in its + computation for each row (r) of the state. All the alternative + macros give the same end values but expand into different ways + of calculating these values. In particular the complex macro + used for dynamically variable block sizes is designed to expand + to a compile time constant whenever possible but will expand to + conditional clauses on some branches (I am grateful to Frank + Yellin for this construction) +*/ + +#define fwd_var(x, r, c) \ + (r == 0 ? (c == 0 ? s(x, 0) : \ + c == 1 ? s(x, 1) : \ + c == 2 ? s(x, 2) : \ + s(x, 3)) : \ + r == 1 ? (c == 0 ? s(x, 1) : \ + c == 1 ? s(x, 2) : \ + c == 2 ? s(x, 3) : \ + s(x, 0)) : \ + r == 2 ? (c == 0 ? s(x, 2) : \ + c == 1 ? s(x, 3) : \ + c == 2 ? s(x, 0) : \ + s(x, 1)) : \ + (c == 0 ? s(x, 3) : \ + c == 1 ? s(x, 0) : \ + c == 2 ? s(x, 1) : \ + s(x, 2))) + +#if defined(FT4_SET) +#undef dec_fmvars +#define fwd_rnd(y, x, k, c) (s(y, c) = (k)[c] ^ four_tables(x, t_use(f, n), fwd_var, rf1, c)) +#elif defined(FT1_SET) +#undef dec_fmvars +#define fwd_rnd(y, x, k, c) (s(y, c) = (k)[c] ^ one_table(x, upr, t_use(f, n), fwd_var, rf1, c)) +#else +#define fwd_rnd(y, x, k, c) \ + (s(y, c) = (k)[c] ^ fwd_mcol(no_table(x, t_use(s, box), fwd_var, rf1, c))) +#endif + +#if defined(FL4_SET) +#define fwd_lrnd(y, x, k, c) (s(y, c) = (k)[c] ^ four_tables(x, t_use(f, l), fwd_var, rf1, c)) +#elif defined(FL1_SET) +#define fwd_lrnd(y, x, k, c) (s(y, c) = (k)[c] ^ one_table(x, ups, t_use(f, l), fwd_var, rf1, c)) +#else +#define fwd_lrnd(y, x, k, c) (s(y, c) = (k)[c] ^ no_table(x, t_use(s, box), fwd_var, rf1, c)) +#endif + +AES_RETURN +aes_xi(encrypt)(const unsigned char* in, unsigned char* out, const aes_encrypt_ctx cx[1]) { + uint32_t locals(b0, b1); + const uint32_t* kp = NULL; +#if defined(dec_fmvars) + dec_fmvars; /* declare variables for fwd_mcol() if needed */ +#endif + + if(cx->inf.b[0] != 10 * AES_BLOCK_SIZE && cx->inf.b[0] != 12 * AES_BLOCK_SIZE && + cx->inf.b[0] != 14 * AES_BLOCK_SIZE) + return EXIT_FAILURE; + + kp = cx->ks; + state_in(b0, in, kp); + +#if(ENC_UNROLL == FULL) + + switch(cx->inf.b[0]) { + case 14 * AES_BLOCK_SIZE: + round(fwd_rnd, b1, b0, kp + 1 * N_COLS); + round(fwd_rnd, b0, b1, kp + 2 * N_COLS); + kp += 2 * N_COLS; + //-fallthrough + case 12 * AES_BLOCK_SIZE: + round(fwd_rnd, b1, b0, kp + 1 * N_COLS); + round(fwd_rnd, b0, b1, kp + 2 * N_COLS); + kp += 2 * N_COLS; + //-fallthrough + case 10 * AES_BLOCK_SIZE: + round(fwd_rnd, b1, b0, kp + 1 * N_COLS); + round(fwd_rnd, b0, b1, kp + 2 * N_COLS); + round(fwd_rnd, b1, b0, kp + 3 * N_COLS); + round(fwd_rnd, b0, b1, kp + 4 * N_COLS); + round(fwd_rnd, b1, b0, kp + 5 * N_COLS); + round(fwd_rnd, b0, b1, kp + 6 * N_COLS); + round(fwd_rnd, b1, b0, kp + 7 * N_COLS); + round(fwd_rnd, b0, b1, kp + 8 * N_COLS); + round(fwd_rnd, b1, b0, kp + 9 * N_COLS); + round(fwd_lrnd, b0, b1, kp + 10 * N_COLS); + //-fallthrough + } + +#else + +#if(ENC_UNROLL == PARTIAL) + { + uint32_t rnd; + for(rnd = 0; rnd < (cx->inf.b[0] >> 5) - 1; ++rnd) { + kp += N_COLS; + round(fwd_rnd, b1, b0, kp); + kp += N_COLS; + round(fwd_rnd, b0, b1, kp); + } + kp += N_COLS; + round(fwd_rnd, b1, b0, kp); +#else + { + uint32_t rnd; + for(rnd = 0; rnd < (cx->inf.b[0] >> 4) - 1; ++rnd) { + kp += N_COLS; + round(fwd_rnd, b1, b0, kp); + l_copy(b0, b1); + } +#endif + kp += N_COLS; + round(fwd_lrnd, b0, b1, kp); + } +#endif + + state_out(out, b0); + return EXIT_SUCCESS; +} + +#endif + +#if(FUNCS_IN_C & DECRYPTION_IN_C) + +/* Visual C++ .Net v7.1 provides the fastest encryption code when using + Pentium optimiation with small code but this is poor for decryption + so we need to control this with the following VC++ pragmas +*/ + +#if defined(_MSC_VER) && !defined(_WIN64) && !defined(__clang__) +#pragma optimize("t", on) +#endif + +/* Given the column (c) of the output state variable, the following + macros give the input state variables which are needed in its + computation for each row (r) of the state. All the alternative + macros give the same end values but expand into different ways + of calculating these values. In particular the complex macro + used for dynamically variable block sizes is designed to expand + to a compile time constant whenever possible but will expand to + conditional clauses on some branches (I am grateful to Frank + Yellin for this construction) +*/ + +#define inv_var(x, r, c) \ + (r == 0 ? (c == 0 ? s(x, 0) : \ + c == 1 ? s(x, 1) : \ + c == 2 ? s(x, 2) : \ + s(x, 3)) : \ + r == 1 ? (c == 0 ? s(x, 3) : \ + c == 1 ? s(x, 0) : \ + c == 2 ? s(x, 1) : \ + s(x, 2)) : \ + r == 2 ? (c == 0 ? s(x, 2) : \ + c == 1 ? s(x, 3) : \ + c == 2 ? s(x, 0) : \ + s(x, 1)) : \ + (c == 0 ? s(x, 1) : \ + c == 1 ? s(x, 2) : \ + c == 2 ? s(x, 3) : \ + s(x, 0))) + +#if defined(IT4_SET) +#undef dec_imvars +#define inv_rnd(y, x, k, c) (s(y, c) = (k)[c] ^ four_tables(x, t_use(i, n), inv_var, rf1, c)) +#elif defined(IT1_SET) +#undef dec_imvars +#define inv_rnd(y, x, k, c) (s(y, c) = (k)[c] ^ one_table(x, upr, t_use(i, n), inv_var, rf1, c)) +#else +#define inv_rnd(y, x, k, c) \ + (s(y, c) = inv_mcol((k)[c] ^ no_table(x, t_use(i, box), inv_var, rf1, c))) +#endif + +#if defined(IL4_SET) +#define inv_lrnd(y, x, k, c) (s(y, c) = (k)[c] ^ four_tables(x, t_use(i, l), inv_var, rf1, c)) +#elif defined(IL1_SET) +#define inv_lrnd(y, x, k, c) (s(y, c) = (k)[c] ^ one_table(x, ups, t_use(i, l), inv_var, rf1, c)) +#else +#define inv_lrnd(y, x, k, c) (s(y, c) = (k)[c] ^ no_table(x, t_use(i, box), inv_var, rf1, c)) +#endif + +/* This code can work with the decryption key schedule in the */ +/* order that is used for encrytpion (where the 1st decryption */ +/* round key is at the high end ot the schedule) or with a key */ +/* schedule that has been reversed to put the 1st decryption */ +/* round key at the low end of the schedule in memory (when */ +/* AES_REV_DKS is defined) */ + +#ifdef AES_REV_DKS +#define key_ofs 0 +#define rnd_key(n) (kp + n * N_COLS) +#else +#define key_ofs 1 +#define rnd_key(n) (kp - n * N_COLS) +#endif + +AES_RETURN +aes_xi(decrypt)(const unsigned char* in, unsigned char* out, const aes_decrypt_ctx cx[1]) { + uint32_t locals(b0, b1); +#if defined(dec_imvars) + dec_imvars; /* declare variables for inv_mcol() if needed */ +#endif + const uint32_t* kp = NULL; + + if(cx->inf.b[0] != 10 * AES_BLOCK_SIZE && cx->inf.b[0] != 12 * AES_BLOCK_SIZE && + cx->inf.b[0] != 14 * AES_BLOCK_SIZE) + return EXIT_FAILURE; + + kp = cx->ks + (key_ofs ? (cx->inf.b[0] >> 2) : 0); + state_in(b0, in, kp); + +#if(DEC_UNROLL == FULL) + + kp = cx->ks + (key_ofs ? 0 : (cx->inf.b[0] >> 2)); + switch(cx->inf.b[0]) { + case 14 * AES_BLOCK_SIZE: + round(inv_rnd, b1, b0, rnd_key(-13)); + round(inv_rnd, b0, b1, rnd_key(-12)); + //-fallthrough + case 12 * AES_BLOCK_SIZE: + round(inv_rnd, b1, b0, rnd_key(-11)); + round(inv_rnd, b0, b1, rnd_key(-10)); + //-fallthrough + case 10 * AES_BLOCK_SIZE: + round(inv_rnd, b1, b0, rnd_key(-9)); + round(inv_rnd, b0, b1, rnd_key(-8)); + round(inv_rnd, b1, b0, rnd_key(-7)); + round(inv_rnd, b0, b1, rnd_key(-6)); + round(inv_rnd, b1, b0, rnd_key(-5)); + round(inv_rnd, b0, b1, rnd_key(-4)); + round(inv_rnd, b1, b0, rnd_key(-3)); + round(inv_rnd, b0, b1, rnd_key(-2)); + round(inv_rnd, b1, b0, rnd_key(-1)); + round(inv_lrnd, b0, b1, rnd_key(0)); + //-fallthrough + } + +#else + +#if(DEC_UNROLL == PARTIAL) + { + uint32_t rnd; + for(rnd = 0; rnd < (cx->inf.b[0] >> 5) - 1; ++rnd) { + kp = rnd_key(1); + round(inv_rnd, b1, b0, kp); + kp = rnd_key(1); + round(inv_rnd, b0, b1, kp); + } + kp = rnd_key(1); + round(inv_rnd, b1, b0, kp); +#else + { + uint32_t rnd; + for(rnd = 0; rnd < (cx->inf.b[0] >> 4) - 1; ++rnd) { + kp = rnd_key(1); + round(inv_rnd, b1, b0, kp); + l_copy(b0, b1); + } +#endif + kp = rnd_key(1); + round(inv_lrnd, b0, b1, kp); + } +#endif + + state_out(out, b0); + return EXIT_SUCCESS; +} + +#endif + +#if defined(__cplusplus) +} +#endif diff --git a/applications/external/flipbip/lib/crypto/aes/aeskey.c b/applications/external/flipbip/lib/crypto/aes/aeskey.c new file mode 100644 index 000000000..0092be439 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/aes/aeskey.c @@ -0,0 +1,662 @@ +/* +--------------------------------------------------------------------------- +Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. + +The redistribution and use of this software (with or without changes) +is allowed without the payment of fees or royalties provided that: + + source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation. + +This software is provided 'as is' with no explicit or implied warranties +in respect of its operation, including, but not limited to, correctness +and fitness for purpose. +--------------------------------------------------------------------------- +Issue Date: 20/12/2007 +*/ + +#include "aesopt.h" +#include "aestab.h" + +#if defined(USE_INTEL_AES_IF_PRESENT) +#include "aes_ni.h" +#else +/* map names here to provide the external API ('name' -> 'aes_name') */ +#define aes_xi(x) aes_##x +#endif + +#ifdef USE_VIA_ACE_IF_PRESENT +#include "aes_via_ace.h" +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +/* Initialise the key schedule from the user supplied key. The key + length can be specified in bytes, with legal values of 16, 24 + and 32, or in bits, with legal values of 128, 192 and 256. These + values correspond with Nk values of 4, 6 and 8 respectively. + + The following macros implement a single cycle in the key + schedule generation process. The number of cycles needed + for each cx->n_col and nk value is: + + nk = 4 5 6 7 8 + ------------------------------ + cx->n_col = 4 10 9 8 7 7 + cx->n_col = 5 14 11 10 9 9 + cx->n_col = 6 19 15 12 11 11 + cx->n_col = 7 21 19 16 13 14 + cx->n_col = 8 29 23 19 17 14 +*/ + +#if defined(REDUCE_CODE_SIZE) +#define ls_box ls_sub +uint32_t ls_sub(const uint32_t t, const uint32_t n); +#define inv_mcol im_sub +uint32_t im_sub(const uint32_t x); +#ifdef ENC_KS_UNROLL +#undef ENC_KS_UNROLL +#endif +#ifdef DEC_KS_UNROLL +#undef DEC_KS_UNROLL +#endif +#endif + +#if(FUNCS_IN_C & ENC_KEYING_IN_C) + +#if defined(AES_128) || defined(AES_VAR) + +#define ke4(k, i) \ + { \ + k[4 * (i) + 4] = ss[0] ^= ls_box(ss[3], 3) ^ t_use(r, c)[i]; \ + k[4 * (i) + 5] = ss[1] ^= ss[0]; \ + k[4 * (i) + 6] = ss[2] ^= ss[1]; \ + k[4 * (i) + 7] = ss[3] ^= ss[2]; \ + } + +AES_RETURN aes_xi(encrypt_key128)(const unsigned char* key, aes_encrypt_ctx cx[1]) { + uint32_t ss[4]; + + cx->ks[0] = ss[0] = word_in(key, 0); + cx->ks[1] = ss[1] = word_in(key, 1); + cx->ks[2] = ss[2] = word_in(key, 2); + cx->ks[3] = ss[3] = word_in(key, 3); + +#ifdef ENC_KS_UNROLL + ke4(cx->ks, 0); + ke4(cx->ks, 1); + ke4(cx->ks, 2); + ke4(cx->ks, 3); + ke4(cx->ks, 4); + ke4(cx->ks, 5); + ke4(cx->ks, 6); + ke4(cx->ks, 7); + ke4(cx->ks, 8); +#else + { + uint32_t i; + for(i = 0; i < 9; ++i) ke4(cx->ks, i); + } +#endif + ke4(cx->ks, 9); + cx->inf.l = 0; + cx->inf.b[0] = 10 * AES_BLOCK_SIZE; + +#ifdef USE_VIA_ACE_IF_PRESENT + if(VIA_ACE_AVAILABLE) cx->inf.b[1] = 0xff; +#endif + return EXIT_SUCCESS; +} + +#endif + +#if defined(AES_192) || defined(AES_VAR) + +#define kef6(k, i) \ + { \ + k[6 * (i) + 6] = ss[0] ^= ls_box(ss[5], 3) ^ t_use(r, c)[i]; \ + k[6 * (i) + 7] = ss[1] ^= ss[0]; \ + k[6 * (i) + 8] = ss[2] ^= ss[1]; \ + k[6 * (i) + 9] = ss[3] ^= ss[2]; \ + } + +#define ke6(k, i) \ + { \ + kef6(k, i); \ + k[6 * (i) + 10] = ss[4] ^= ss[3]; \ + k[6 * (i) + 11] = ss[5] ^= ss[4]; \ + } + +AES_RETURN aes_xi(encrypt_key192)(const unsigned char* key, aes_encrypt_ctx cx[1]) { + uint32_t ss[6]; + + cx->ks[0] = ss[0] = word_in(key, 0); + cx->ks[1] = ss[1] = word_in(key, 1); + cx->ks[2] = ss[2] = word_in(key, 2); + cx->ks[3] = ss[3] = word_in(key, 3); + cx->ks[4] = ss[4] = word_in(key, 4); + cx->ks[5] = ss[5] = word_in(key, 5); + +#ifdef ENC_KS_UNROLL + ke6(cx->ks, 0); + ke6(cx->ks, 1); + ke6(cx->ks, 2); + ke6(cx->ks, 3); + ke6(cx->ks, 4); + ke6(cx->ks, 5); + ke6(cx->ks, 6); +#else + { + uint32_t i; + for(i = 0; i < 7; ++i) ke6(cx->ks, i); + } +#endif + kef6(cx->ks, 7); + cx->inf.l = 0; + cx->inf.b[0] = 12 * AES_BLOCK_SIZE; + +#ifdef USE_VIA_ACE_IF_PRESENT + if(VIA_ACE_AVAILABLE) cx->inf.b[1] = 0xff; +#endif + return EXIT_SUCCESS; +} + +#endif + +#if defined(AES_256) || defined(AES_VAR) + +#define kef8(k, i) \ + { \ + k[8 * (i) + 8] = ss[0] ^= ls_box(ss[7], 3) ^ t_use(r, c)[i]; \ + k[8 * (i) + 9] = ss[1] ^= ss[0]; \ + k[8 * (i) + 10] = ss[2] ^= ss[1]; \ + k[8 * (i) + 11] = ss[3] ^= ss[2]; \ + } + +#define ke8(k, i) \ + { \ + kef8(k, i); \ + k[8 * (i) + 12] = ss[4] ^= ls_box(ss[3], 0); \ + k[8 * (i) + 13] = ss[5] ^= ss[4]; \ + k[8 * (i) + 14] = ss[6] ^= ss[5]; \ + k[8 * (i) + 15] = ss[7] ^= ss[6]; \ + } + +AES_RETURN aes_xi(encrypt_key256)(const unsigned char* key, aes_encrypt_ctx cx[1]) { + uint32_t ss[8]; + + cx->ks[0] = ss[0] = word_in(key, 0); + cx->ks[1] = ss[1] = word_in(key, 1); + cx->ks[2] = ss[2] = word_in(key, 2); + cx->ks[3] = ss[3] = word_in(key, 3); + cx->ks[4] = ss[4] = word_in(key, 4); + cx->ks[5] = ss[5] = word_in(key, 5); + cx->ks[6] = ss[6] = word_in(key, 6); + cx->ks[7] = ss[7] = word_in(key, 7); + +#ifdef ENC_KS_UNROLL + ke8(cx->ks, 0); + ke8(cx->ks, 1); + ke8(cx->ks, 2); + ke8(cx->ks, 3); + ke8(cx->ks, 4); + ke8(cx->ks, 5); +#else + { + uint32_t i; + for(i = 0; i < 6; ++i) ke8(cx->ks, i); + } +#endif + kef8(cx->ks, 6); + cx->inf.l = 0; + cx->inf.b[0] = 14 * AES_BLOCK_SIZE; + +#ifdef USE_VIA_ACE_IF_PRESENT + if(VIA_ACE_AVAILABLE) cx->inf.b[1] = 0xff; +#endif + return EXIT_SUCCESS; +} + +#endif + +#endif + +#if(FUNCS_IN_C & DEC_KEYING_IN_C) + +/* this is used to store the decryption round keys */ +/* in forward or reverse order */ + +#ifdef AES_REV_DKS +#define v(n, i) ((n) - (i) + 2 * ((i)&3)) +#else +#define v(n, i) (i) +#endif + +#if DEC_ROUND == NO_TABLES +#define ff(x) (x) +#else +#define ff(x) inv_mcol(x) +#if defined(dec_imvars) +#define d_vars dec_imvars +#endif +#endif + +#if defined(AES_128) || defined(AES_VAR) + +#define k4e(k, i) \ + { \ + k[v(40, (4 * (i)) + 4)] = ss[0] ^= ls_box(ss[3], 3) ^ t_use(r, c)[i]; \ + k[v(40, (4 * (i)) + 5)] = ss[1] ^= ss[0]; \ + k[v(40, (4 * (i)) + 6)] = ss[2] ^= ss[1]; \ + k[v(40, (4 * (i)) + 7)] = ss[3] ^= ss[2]; \ + } + +#if 1 + +#define kdf4(k, i) \ + { \ + ss[0] = ss[0] ^ ss[2] ^ ss[1] ^ ss[3]; \ + ss[1] = ss[1] ^ ss[3]; \ + ss[2] = ss[2] ^ ss[3]; \ + ss[4] = ls_box(ss[(i + 3) % 4], 3) ^ t_use(r, c)[i]; \ + ss[i % 4] ^= ss[4]; \ + ss[4] ^= k[v(40, (4 * (i)))]; \ + k[v(40, (4 * (i)) + 4)] = ff(ss[4]); \ + ss[4] ^= k[v(40, (4 * (i)) + 1)]; \ + k[v(40, (4 * (i)) + 5)] = ff(ss[4]); \ + ss[4] ^= k[v(40, (4 * (i)) + 2)]; \ + k[v(40, (4 * (i)) + 6)] = ff(ss[4]); \ + ss[4] ^= k[v(40, (4 * (i)) + 3)]; \ + k[v(40, (4 * (i)) + 7)] = ff(ss[4]); \ + } + +#define kd4(k, i) \ + { \ + ss[4] = ls_box(ss[(i + 3) % 4], 3) ^ t_use(r, c)[i]; \ + ss[i % 4] ^= ss[4]; \ + ss[4] = ff(ss[4]); \ + k[v(40, (4 * (i)) + 4)] = ss[4] ^= k[v(40, (4 * (i)))]; \ + k[v(40, (4 * (i)) + 5)] = ss[4] ^= k[v(40, (4 * (i)) + 1)]; \ + k[v(40, (4 * (i)) + 6)] = ss[4] ^= k[v(40, (4 * (i)) + 2)]; \ + k[v(40, (4 * (i)) + 7)] = ss[4] ^= k[v(40, (4 * (i)) + 3)]; \ + } + +#define kdl4(k, i) \ + { \ + ss[4] = ls_box(ss[(i + 3) % 4], 3) ^ t_use(r, c)[i]; \ + ss[i % 4] ^= ss[4]; \ + k[v(40, (4 * (i)) + 4)] = (ss[0] ^= ss[1]) ^ ss[2] ^ ss[3]; \ + k[v(40, (4 * (i)) + 5)] = ss[1] ^ ss[3]; \ + k[v(40, (4 * (i)) + 6)] = ss[0]; \ + k[v(40, (4 * (i)) + 7)] = ss[1]; \ + } + +#else + +#define kdf4(k, i) \ + { \ + ss[0] ^= ls_box(ss[3], 3) ^ t_use(r, c)[i]; \ + k[v(40, (4 * (i)) + 4)] = ff(ss[0]); \ + ss[1] ^= ss[0]; \ + k[v(40, (4 * (i)) + 5)] = ff(ss[1]); \ + ss[2] ^= ss[1]; \ + k[v(40, (4 * (i)) + 6)] = ff(ss[2]); \ + ss[3] ^= ss[2]; \ + k[v(40, (4 * (i)) + 7)] = ff(ss[3]); \ + } + +#define kd4(k, i) \ + { \ + ss[4] = ls_box(ss[3], 3) ^ t_use(r, c)[i]; \ + ss[0] ^= ss[4]; \ + ss[4] = ff(ss[4]); \ + k[v(40, (4 * (i)) + 4)] = ss[4] ^= k[v(40, (4 * (i)))]; \ + ss[1] ^= ss[0]; \ + k[v(40, (4 * (i)) + 5)] = ss[4] ^= k[v(40, (4 * (i)) + 1)]; \ + ss[2] ^= ss[1]; \ + k[v(40, (4 * (i)) + 6)] = ss[4] ^= k[v(40, (4 * (i)) + 2)]; \ + ss[3] ^= ss[2]; \ + k[v(40, (4 * (i)) + 7)] = ss[4] ^= k[v(40, (4 * (i)) + 3)]; \ + } + +#define kdl4(k, i) \ + { \ + ss[0] ^= ls_box(ss[3], 3) ^ t_use(r, c)[i]; \ + k[v(40, (4 * (i)) + 4)] = ss[0]; \ + ss[1] ^= ss[0]; \ + k[v(40, (4 * (i)) + 5)] = ss[1]; \ + ss[2] ^= ss[1]; \ + k[v(40, (4 * (i)) + 6)] = ss[2]; \ + ss[3] ^= ss[2]; \ + k[v(40, (4 * (i)) + 7)] = ss[3]; \ + } + +#endif + +AES_RETURN aes_xi(decrypt_key128)(const unsigned char* key, aes_decrypt_ctx cx[1]) { + uint32_t ss[5]; +#if defined(d_vars) + d_vars; +#endif + + cx->ks[v(40, (0))] = ss[0] = word_in(key, 0); + cx->ks[v(40, (1))] = ss[1] = word_in(key, 1); + cx->ks[v(40, (2))] = ss[2] = word_in(key, 2); + cx->ks[v(40, (3))] = ss[3] = word_in(key, 3); + +#ifdef DEC_KS_UNROLL + kdf4(cx->ks, 0); + kd4(cx->ks, 1); + kd4(cx->ks, 2); + kd4(cx->ks, 3); + kd4(cx->ks, 4); + kd4(cx->ks, 5); + kd4(cx->ks, 6); + kd4(cx->ks, 7); + kd4(cx->ks, 8); + kdl4(cx->ks, 9); +#else + { + uint32_t i; + for(i = 0; i < 10; ++i) k4e(cx->ks, i); +#if !(DEC_ROUND == NO_TABLES) + for(i = N_COLS; i < 10 * N_COLS; ++i) cx->ks[i] = inv_mcol(cx->ks[i]); +#endif + } +#endif + cx->inf.l = 0; + cx->inf.b[0] = 10 * AES_BLOCK_SIZE; + +#ifdef USE_VIA_ACE_IF_PRESENT + if(VIA_ACE_AVAILABLE) cx->inf.b[1] = 0xff; +#endif + return EXIT_SUCCESS; +} + +#endif + +#if defined(AES_192) || defined(AES_VAR) + +#define k6ef(k, i) \ + { \ + k[v(48, (6 * (i)) + 6)] = ss[0] ^= ls_box(ss[5], 3) ^ t_use(r, c)[i]; \ + k[v(48, (6 * (i)) + 7)] = ss[1] ^= ss[0]; \ + k[v(48, (6 * (i)) + 8)] = ss[2] ^= ss[1]; \ + k[v(48, (6 * (i)) + 9)] = ss[3] ^= ss[2]; \ + } + +#define k6e(k, i) \ + { \ + k6ef(k, i); \ + k[v(48, (6 * (i)) + 10)] = ss[4] ^= ss[3]; \ + k[v(48, (6 * (i)) + 11)] = ss[5] ^= ss[4]; \ + } + +#define kdf6(k, i) \ + { \ + ss[0] ^= ls_box(ss[5], 3) ^ t_use(r, c)[i]; \ + k[v(48, (6 * (i)) + 6)] = ff(ss[0]); \ + ss[1] ^= ss[0]; \ + k[v(48, (6 * (i)) + 7)] = ff(ss[1]); \ + ss[2] ^= ss[1]; \ + k[v(48, (6 * (i)) + 8)] = ff(ss[2]); \ + ss[3] ^= ss[2]; \ + k[v(48, (6 * (i)) + 9)] = ff(ss[3]); \ + ss[4] ^= ss[3]; \ + k[v(48, (6 * (i)) + 10)] = ff(ss[4]); \ + ss[5] ^= ss[4]; \ + k[v(48, (6 * (i)) + 11)] = ff(ss[5]); \ + } + +#define kd6(k, i) \ + { \ + ss[6] = ls_box(ss[5], 3) ^ t_use(r, c)[i]; \ + ss[0] ^= ss[6]; \ + ss[6] = ff(ss[6]); \ + k[v(48, (6 * (i)) + 6)] = ss[6] ^= k[v(48, (6 * (i)))]; \ + ss[1] ^= ss[0]; \ + k[v(48, (6 * (i)) + 7)] = ss[6] ^= k[v(48, (6 * (i)) + 1)]; \ + ss[2] ^= ss[1]; \ + k[v(48, (6 * (i)) + 8)] = ss[6] ^= k[v(48, (6 * (i)) + 2)]; \ + ss[3] ^= ss[2]; \ + k[v(48, (6 * (i)) + 9)] = ss[6] ^= k[v(48, (6 * (i)) + 3)]; \ + ss[4] ^= ss[3]; \ + k[v(48, (6 * (i)) + 10)] = ss[6] ^= k[v(48, (6 * (i)) + 4)]; \ + ss[5] ^= ss[4]; \ + k[v(48, (6 * (i)) + 11)] = ss[6] ^= k[v(48, (6 * (i)) + 5)]; \ + } + +#define kdl6(k, i) \ + { \ + ss[0] ^= ls_box(ss[5], 3) ^ t_use(r, c)[i]; \ + k[v(48, (6 * (i)) + 6)] = ss[0]; \ + ss[1] ^= ss[0]; \ + k[v(48, (6 * (i)) + 7)] = ss[1]; \ + ss[2] ^= ss[1]; \ + k[v(48, (6 * (i)) + 8)] = ss[2]; \ + ss[3] ^= ss[2]; \ + k[v(48, (6 * (i)) + 9)] = ss[3]; \ + } + +AES_RETURN aes_xi(decrypt_key192)(const unsigned char* key, aes_decrypt_ctx cx[1]) { + uint32_t ss[7]; +#if defined(d_vars) + d_vars; +#endif + + cx->ks[v(48, (0))] = ss[0] = word_in(key, 0); + cx->ks[v(48, (1))] = ss[1] = word_in(key, 1); + cx->ks[v(48, (2))] = ss[2] = word_in(key, 2); + cx->ks[v(48, (3))] = ss[3] = word_in(key, 3); + +#ifdef DEC_KS_UNROLL + ss[4] = word_in(key, 4); + ss[5] = word_in(key, 5); + cx->ks[v(48, (4))] = ff(ss[4]); + cx->ks[v(48, (5))] = ff(ss[5]); + kdf6(cx->ks, 0); + kd6(cx->ks, 1); + kd6(cx->ks, 2); + kd6(cx->ks, 3); + kd6(cx->ks, 4); + kd6(cx->ks, 5); + kd6(cx->ks, 6); + kdl6(cx->ks, 7); +#else + cx->ks[v(48, (4))] = ss[4] = word_in(key, 4); + cx->ks[v(48, (5))] = ss[5] = word_in(key, 5); + { + uint32_t i; + + for(i = 0; i < 7; ++i) k6e(cx->ks, i); + k6ef(cx->ks, 7); +#if !(DEC_ROUND == NO_TABLES) + for(i = N_COLS; i < 12 * N_COLS; ++i) cx->ks[i] = inv_mcol(cx->ks[i]); +#endif + } +#endif + cx->inf.l = 0; + cx->inf.b[0] = 12 * AES_BLOCK_SIZE; + +#ifdef USE_VIA_ACE_IF_PRESENT + if(VIA_ACE_AVAILABLE) cx->inf.b[1] = 0xff; +#endif + return EXIT_SUCCESS; +} + +#endif + +#if defined(AES_256) || defined(AES_VAR) + +#define k8ef(k, i) \ + { \ + k[v(56, (8 * (i)) + 8)] = ss[0] ^= ls_box(ss[7], 3) ^ t_use(r, c)[i]; \ + k[v(56, (8 * (i)) + 9)] = ss[1] ^= ss[0]; \ + k[v(56, (8 * (i)) + 10)] = ss[2] ^= ss[1]; \ + k[v(56, (8 * (i)) + 11)] = ss[3] ^= ss[2]; \ + } + +#define k8e(k, i) \ + { \ + k8ef(k, i); \ + k[v(56, (8 * (i)) + 12)] = ss[4] ^= ls_box(ss[3], 0); \ + k[v(56, (8 * (i)) + 13)] = ss[5] ^= ss[4]; \ + k[v(56, (8 * (i)) + 14)] = ss[6] ^= ss[5]; \ + k[v(56, (8 * (i)) + 15)] = ss[7] ^= ss[6]; \ + } + +#define kdf8(k, i) \ + { \ + ss[0] ^= ls_box(ss[7], 3) ^ t_use(r, c)[i]; \ + k[v(56, (8 * (i)) + 8)] = ff(ss[0]); \ + ss[1] ^= ss[0]; \ + k[v(56, (8 * (i)) + 9)] = ff(ss[1]); \ + ss[2] ^= ss[1]; \ + k[v(56, (8 * (i)) + 10)] = ff(ss[2]); \ + ss[3] ^= ss[2]; \ + k[v(56, (8 * (i)) + 11)] = ff(ss[3]); \ + ss[4] ^= ls_box(ss[3], 0); \ + k[v(56, (8 * (i)) + 12)] = ff(ss[4]); \ + ss[5] ^= ss[4]; \ + k[v(56, (8 * (i)) + 13)] = ff(ss[5]); \ + ss[6] ^= ss[5]; \ + k[v(56, (8 * (i)) + 14)] = ff(ss[6]); \ + ss[7] ^= ss[6]; \ + k[v(56, (8 * (i)) + 15)] = ff(ss[7]); \ + } + +#define kd8(k, i) \ + { \ + ss[8] = ls_box(ss[7], 3) ^ t_use(r, c)[i]; \ + ss[0] ^= ss[8]; \ + ss[8] = ff(ss[8]); \ + k[v(56, (8 * (i)) + 8)] = ss[8] ^= k[v(56, (8 * (i)))]; \ + ss[1] ^= ss[0]; \ + k[v(56, (8 * (i)) + 9)] = ss[8] ^= k[v(56, (8 * (i)) + 1)]; \ + ss[2] ^= ss[1]; \ + k[v(56, (8 * (i)) + 10)] = ss[8] ^= k[v(56, (8 * (i)) + 2)]; \ + ss[3] ^= ss[2]; \ + k[v(56, (8 * (i)) + 11)] = ss[8] ^= k[v(56, (8 * (i)) + 3)]; \ + ss[8] = ls_box(ss[3], 0); \ + ss[4] ^= ss[8]; \ + ss[8] = ff(ss[8]); \ + k[v(56, (8 * (i)) + 12)] = ss[8] ^= k[v(56, (8 * (i)) + 4)]; \ + ss[5] ^= ss[4]; \ + k[v(56, (8 * (i)) + 13)] = ss[8] ^= k[v(56, (8 * (i)) + 5)]; \ + ss[6] ^= ss[5]; \ + k[v(56, (8 * (i)) + 14)] = ss[8] ^= k[v(56, (8 * (i)) + 6)]; \ + ss[7] ^= ss[6]; \ + k[v(56, (8 * (i)) + 15)] = ss[8] ^= k[v(56, (8 * (i)) + 7)]; \ + } + +#define kdl8(k, i) \ + { \ + ss[0] ^= ls_box(ss[7], 3) ^ t_use(r, c)[i]; \ + k[v(56, (8 * (i)) + 8)] = ss[0]; \ + ss[1] ^= ss[0]; \ + k[v(56, (8 * (i)) + 9)] = ss[1]; \ + ss[2] ^= ss[1]; \ + k[v(56, (8 * (i)) + 10)] = ss[2]; \ + ss[3] ^= ss[2]; \ + k[v(56, (8 * (i)) + 11)] = ss[3]; \ + } + +AES_RETURN aes_xi(decrypt_key256)(const unsigned char* key, aes_decrypt_ctx cx[1]) { + uint32_t ss[9]; +#if defined(d_vars) + d_vars; +#endif + + cx->ks[v(56, (0))] = ss[0] = word_in(key, 0); + cx->ks[v(56, (1))] = ss[1] = word_in(key, 1); + cx->ks[v(56, (2))] = ss[2] = word_in(key, 2); + cx->ks[v(56, (3))] = ss[3] = word_in(key, 3); + +#ifdef DEC_KS_UNROLL + ss[4] = word_in(key, 4); + ss[5] = word_in(key, 5); + ss[6] = word_in(key, 6); + ss[7] = word_in(key, 7); + cx->ks[v(56, (4))] = ff(ss[4]); + cx->ks[v(56, (5))] = ff(ss[5]); + cx->ks[v(56, (6))] = ff(ss[6]); + cx->ks[v(56, (7))] = ff(ss[7]); + kdf8(cx->ks, 0); + kd8(cx->ks, 1); + kd8(cx->ks, 2); + kd8(cx->ks, 3); + kd8(cx->ks, 4); + kd8(cx->ks, 5); + kdl8(cx->ks, 6); +#else + cx->ks[v(56, (4))] = ss[4] = word_in(key, 4); + cx->ks[v(56, (5))] = ss[5] = word_in(key, 5); + cx->ks[v(56, (6))] = ss[6] = word_in(key, 6); + cx->ks[v(56, (7))] = ss[7] = word_in(key, 7); + { + uint32_t i; + + for(i = 0; i < 6; ++i) k8e(cx->ks, i); + k8ef(cx->ks, 6); +#if !(DEC_ROUND == NO_TABLES) + for(i = N_COLS; i < 14 * N_COLS; ++i) cx->ks[i] = inv_mcol(cx->ks[i]); +#endif + } +#endif + cx->inf.l = 0; + cx->inf.b[0] = 14 * AES_BLOCK_SIZE; + +#ifdef USE_VIA_ACE_IF_PRESENT + if(VIA_ACE_AVAILABLE) cx->inf.b[1] = 0xff; +#endif + return EXIT_SUCCESS; +} + +#endif + +#endif + +#if defined(AES_VAR) + +AES_RETURN aes_encrypt_key(const unsigned char* key, int key_len, aes_encrypt_ctx cx[1]) { + switch(key_len) { + case 16: + case 128: + return aes_encrypt_key128(key, cx); + case 24: + case 192: + return aes_encrypt_key192(key, cx); + case 32: + case 256: + return aes_encrypt_key256(key, cx); + default: + return EXIT_FAILURE; + } +} + +AES_RETURN aes_decrypt_key(const unsigned char* key, int key_len, aes_decrypt_ctx cx[1]) { + switch(key_len) { + case 16: + case 128: + return aes_decrypt_key128(key, cx); + case 24: + case 192: + return aes_decrypt_key192(key, cx); + case 32: + case 256: + return aes_decrypt_key256(key, cx); + default: + return EXIT_FAILURE; + } +} + +#endif + +#if defined(__cplusplus) +} +#endif diff --git a/applications/external/flipbip/lib/crypto/aes/aesopt.h b/applications/external/flipbip/lib/crypto/aes/aesopt.h new file mode 100644 index 000000000..6d4de004f --- /dev/null +++ b/applications/external/flipbip/lib/crypto/aes/aesopt.h @@ -0,0 +1,793 @@ +/* +--------------------------------------------------------------------------- +Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. + +The redistribution and use of this software (with or without changes) +is allowed without the payment of fees or royalties provided that: + + source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation. + +This software is provided 'as is' with no explicit or implied warranties +in respect of its operation, including, but not limited to, correctness +and fitness for purpose. +--------------------------------------------------------------------------- +Issue Date: 20/12/2007 + + This file contains the compilation options for AES (Rijndael) and code + that is common across encryption, key scheduling and table generation. + + OPERATION + + These source code files implement the AES algorithm Rijndael designed by + Joan Daemen and Vincent Rijmen. This version is designed for the standard + block size of 16 bytes and for key sizes of 128, 192 and 256 bits (16, 24 + and 32 bytes). + + This version is designed for flexibility and speed using operations on + 32-bit words rather than operations on bytes. It can be compiled with + either big or little endian internal byte order but is faster when the + native byte order for the processor is used. + + THE CIPHER INTERFACE + + The cipher interface is implemented as an array of bytes in which lower + AES bit sequence indexes map to higher numeric significance within bytes. + + uint8_t (an unsigned 8-bit type) + uint32_t (an unsigned 32-bit type) + struct aes_encrypt_ctx (structure for the cipher encryption context) + struct aes_decrypt_ctx (structure for the cipher decryption context) + AES_RETURN the function return type + + C subroutine calls: + + AES_RETURN aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1]); + AES_RETURN aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1]); + AES_RETURN aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1]); + AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out, + const aes_encrypt_ctx cx[1]); + + AES_RETURN aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1]); + AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1]); + AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1]); + AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out, + const aes_decrypt_ctx cx[1]); + + IMPORTANT NOTE: If you are using this C interface with dynamic tables make sure that + you call aes_init() before AES is used so that the tables are initialised. + + C++ aes class subroutines: + + Class AESencrypt for encryption + + Constructors: + AESencrypt(void) + AESencrypt(const unsigned char *key) - 128 bit key + Members: + AES_RETURN key128(const unsigned char *key) + AES_RETURN key192(const unsigned char *key) + AES_RETURN key256(const unsigned char *key) + AES_RETURN encrypt(const unsigned char *in, unsigned char *out) const + + Class AESdecrypt for encryption + Constructors: + AESdecrypt(void) + AESdecrypt(const unsigned char *key) - 128 bit key + Members: + AES_RETURN key128(const unsigned char *key) + AES_RETURN key192(const unsigned char *key) + AES_RETURN key256(const unsigned char *key) + AES_RETURN decrypt(const unsigned char *in, unsigned char *out) const +*/ + +#if !defined(_AESOPT_H) +#define _AESOPT_H + +#if defined(__cplusplus) +#include "aescpp.h" +#else +#include "aes.h" +#endif + +/* PLATFORM SPECIFIC INCLUDES */ + +#define IS_BIG_ENDIAN 4321 +#define IS_LITTLE_ENDIAN 1234 +#define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN + +/* CONFIGURATION - THE USE OF DEFINES + + Later in this section there are a number of defines that control the + operation of the code. In each section, the purpose of each define is + explained so that the relevant form can be included or excluded by + setting either 1's or 0's respectively on the branches of the related + #if clauses. The following local defines should not be changed. +*/ + +#define ENCRYPTION_IN_C 1 +#define DECRYPTION_IN_C 2 +#define ENC_KEYING_IN_C 4 +#define DEC_KEYING_IN_C 8 + +#define NO_TABLES 0 +#define ONE_TABLE 1 +#define FOUR_TABLES 4 +#define NONE 0 +#define PARTIAL 1 +#define FULL 2 + +/* --- START OF USER CONFIGURED OPTIONS --- */ + +/* 1. BYTE ORDER WITHIN 32 BIT WORDS + + The fundamental data processing units in Rijndael are 8-bit bytes. The + input, output and key input are all enumerated arrays of bytes in which + bytes are numbered starting at zero and increasing to one less than the + number of bytes in the array in question. This enumeration is only used + for naming bytes and does not imply any adjacency or order relationship + from one byte to another. When these inputs and outputs are considered + as bit sequences, bits 8*n to 8*n+7 of the bit sequence are mapped to + byte[n] with bit 8n+i in the sequence mapped to bit 7-i within the byte. + In this implementation bits are numbered from 0 to 7 starting at the + numerically least significant end of each byte (bit n represents 2^n). + + However, Rijndael can be implemented more efficiently using 32-bit + words by packing bytes into words so that bytes 4*n to 4*n+3 are placed + into word[n]. While in principle these bytes can be assembled into words + in any positions, this implementation only supports the two formats in + which bytes in adjacent positions within words also have adjacent byte + numbers. This order is called big-endian if the lowest numbered bytes + in words have the highest numeric significance and little-endian if the + opposite applies. + + This code can work in either order irrespective of the order used by the + machine on which it runs. Normally the internal byte order will be set + to the order of the processor on which the code is to be run but this + define can be used to reverse this in special situations + + WARNING: Assembler code versions rely on PLATFORM_BYTE_ORDER being set. + This define will hence be redefined later (in section 4) if necessary +*/ + +#if 1 +#define ALGORITHM_BYTE_ORDER PLATFORM_BYTE_ORDER +#elif 0 +#define ALGORITHM_BYTE_ORDER IS_LITTLE_ENDIAN +#elif 0 +#define ALGORITHM_BYTE_ORDER IS_BIG_ENDIAN +#else +#error The algorithm byte order is not defined +#endif + +/* 2. Intel AES AND VIA ACE SUPPORT */ + +#if defined(__GNUC__) && defined(__i386__) && !defined(__BEOS__) || \ + defined(_WIN32) && defined(_M_IX86) && \ + !(defined(_WIN64) || defined(_WIN32_WCE) || defined(_MSC_VER) && (_MSC_VER <= 800)) +#define VIA_ACE_POSSIBLE +#endif + +/* AESNI is supported by all Windows x64 compilers, but for Linux/GCC + we have to test for SSE 2, SSE 3, and AES to before enabling it; */ +#if !defined(INTEL_AES_POSSIBLE) +#if defined(_WIN64) && defined(_MSC_VER) || defined(__GNUC__) && defined(__x86_64__) && \ + defined(__SSE2__) && defined(__SSE3__) && \ + defined(__AES__) +#define INTEL_AES_POSSIBLE +#endif +#endif + +/* Define this option if support for the Intel AESNI is required + If USE_INTEL_AES_IF_PRESENT is defined then AESNI will be used + if it is detected (both present and enabled). + + AESNI uses a decryption key schedule with the first decryption + round key at the high end of the key scedule with the following + round keys at lower positions in memory. So AES_REV_DKS must NOT + be defined when AESNI will be used. Although it is unlikely that + assembler code will be used with an AESNI build, if it is then + AES_REV_DKS must NOT be defined when the assembler files are + built (the definition of USE_INTEL_AES_IF_PRESENT in the assembler + code files must match that here if they are used). +*/ + +#if 0 && defined(INTEL_AES_POSSIBLE) && !defined(USE_INTEL_AES_IF_PRESENT) +#define USE_INTEL_AES_IF_PRESENT +#endif + +/* Define this option if support for the VIA ACE is required. This uses + inline assembler instructions and is only implemented for the Microsoft, + Intel and GCC compilers. If VIA ACE is known to be present, then defining + ASSUME_VIA_ACE_PRESENT will remove the ordinary encryption/decryption + code. If USE_VIA_ACE_IF_PRESENT is defined then VIA ACE will be used if + it is detected (both present and enabled) but the normal AES code will + also be present. + + When VIA ACE is to be used, all AES encryption contexts MUST be 16 byte + aligned; other input/output buffers do not need to be 16 byte aligned + but there are very large performance gains if this can be arranged. + VIA ACE also requires the decryption key schedule to be in reverse + order (which later checks below ensure). + + AES_REV_DKS must be set for assembler code used with a VIA ACE build +*/ + +#if 0 && defined(VIA_ACE_POSSIBLE) && !defined(USE_VIA_ACE_IF_PRESENT) +#define USE_VIA_ACE_IF_PRESENT +#endif + +#if 0 && defined(VIA_ACE_POSSIBLE) && !defined(ASSUME_VIA_ACE_PRESENT) +#define ASSUME_VIA_ACE_PRESENT +#endif + +/* 3. ASSEMBLER SUPPORT + + This define (which can be on the command line) enables the use of the + assembler code routines for encryption, decryption and key scheduling + as follows: + + ASM_X86_V1C uses the assembler (aes_x86_v1.asm) with large tables for + encryption and decryption and but with key scheduling in C + ASM_X86_V2 uses assembler (aes_x86_v2.asm) with compressed tables for + encryption, decryption and key scheduling + ASM_X86_V2C uses assembler (aes_x86_v2.asm) with compressed tables for + encryption and decryption and but with key scheduling in C + ASM_AMD64_C uses assembler (aes_amd64.asm) with compressed tables for + encryption and decryption and but with key scheduling in C + + Change one 'if 0' below to 'if 1' to select the version or define + as a compilation option. +*/ + +#if 0 && !defined(ASM_X86_V1C) +#define ASM_X86_V1C +#elif 0 && !defined(ASM_X86_V2) +#define ASM_X86_V2 +#elif 0 && !defined(ASM_X86_V2C) +#define ASM_X86_V2C +#elif 0 && !defined(ASM_AMD64_C) +#define ASM_AMD64_C +#endif + +#if defined(__i386) || defined(_M_IX86) +#define A32_ +#elif defined(__x86_64__) || defined(_M_X64) +#define A64_ +#endif + +#if(defined(ASM_X86_V1C) || defined(ASM_X86_V2) || defined(ASM_X86_V2C)) && !defined(A32_) || \ + defined(ASM_AMD64_C) && !defined(A64_) +#error Assembler code is only available for x86 and AMD64 systems +#endif + +/* 4. FAST INPUT/OUTPUT OPERATIONS. + + On some machines it is possible to improve speed by transferring the + bytes in the input and output arrays to and from the internal 32-bit + variables by addressing these arrays as if they are arrays of 32-bit + words. On some machines this will always be possible but there may + be a large performance penalty if the byte arrays are not aligned on + the normal word boundaries. On other machines this technique will + lead to memory access errors when such 32-bit word accesses are not + properly aligned. The option SAFE_IO avoids such problems but will + often be slower on those machines that support misaligned access + (especially so if care is taken to align the input and output byte + arrays on 32-bit word boundaries). If SAFE_IO is not defined it is + assumed that access to byte arrays as if they are arrays of 32-bit + words will not cause problems when such accesses are misaligned. +*/ +#if 1 && !defined(_MSC_VER) +#define SAFE_IO +#endif + +/* 5. LOOP UNROLLING + + The code for encryption and decrytpion cycles through a number of rounds + that can be implemented either in a loop or by expanding the code into a + long sequence of instructions, the latter producing a larger program but + one that will often be much faster. The latter is called loop unrolling. + There are also potential speed advantages in expanding two iterations in + a loop with half the number of iterations, which is called partial loop + unrolling. The following options allow partial or full loop unrolling + to be set independently for encryption and decryption +*/ +#if 1 +#define ENC_UNROLL FULL +#elif 0 +#define ENC_UNROLL PARTIAL +#else +#define ENC_UNROLL NONE +#endif + +#if 1 +#define DEC_UNROLL FULL +#elif 0 +#define DEC_UNROLL PARTIAL +#else +#define DEC_UNROLL NONE +#endif + +#if 1 +#define ENC_KS_UNROLL +#endif + +#if 1 +#define DEC_KS_UNROLL +#endif + +/* 6. FAST FINITE FIELD OPERATIONS + + If this section is included, tables are used to provide faster finite + field arithmetic (this has no effect if STATIC_TABLES is defined). +*/ +#if 1 +#define FF_TABLES +#endif + +/* 7. INTERNAL STATE VARIABLE FORMAT + + The internal state of Rijndael is stored in a number of local 32-bit + word varaibles which can be defined either as an array or as individual + names variables. Include this section if you want to store these local + varaibles in arrays. Otherwise individual local variables will be used. +*/ +#if 1 +#define ARRAYS +#endif + +/* 8. FIXED OR DYNAMIC TABLES + + When this section is included the tables used by the code are compiled + statically into the binary file. Otherwise the subroutine aes_init() + must be called to compute them before the code is first used. +*/ +#if 1 && !(defined(_MSC_VER) && (_MSC_VER <= 800)) +#define STATIC_TABLES +#endif + +/* 9. MASKING OR CASTING FROM LONGER VALUES TO BYTES + + In some systems it is better to mask longer values to extract bytes + rather than using a cast. This option allows this choice. +*/ +#if 0 +#define to_byte(x) ((uint8_t)(x)) +#else +#define to_byte(x) ((x)&0xff) +#endif + +/* 10. TABLE ALIGNMENT + + On some sytsems speed will be improved by aligning the AES large lookup + tables on particular boundaries. This define should be set to a power of + two giving the desired alignment. It can be left undefined if alignment + is not needed. This option is specific to the Microsft VC++ compiler - + it seems to sometimes cause trouble for the VC++ version 6 compiler. +*/ + +#if 1 && defined(_MSC_VER) && (_MSC_VER >= 1300) +#define TABLE_ALIGN 32 +#endif + +/* 11. REDUCE CODE AND TABLE SIZE + + This replaces some expanded macros with function calls if AES_ASM_V2 or + AES_ASM_V2C are defined +*/ + +#if 1 && (defined(ASM_X86_V2) || defined(ASM_X86_V2C)) +#define REDUCE_CODE_SIZE +#endif + +/* 12. TABLE OPTIONS + + This cipher proceeds by repeating in a number of cycles known as 'rounds' + which are implemented by a round function which can optionally be speeded + up using tables. The basic tables are each 256 32-bit words, with either + one or four tables being required for each round function depending on + how much speed is required. The encryption and decryption round functions + are different and the last encryption and decrytpion round functions are + different again making four different round functions in all. + + This means that: + 1. Normal encryption and decryption rounds can each use either 0, 1 + or 4 tables and table spaces of 0, 1024 or 4096 bytes each. + 2. The last encryption and decryption rounds can also use either 0, 1 + or 4 tables and table spaces of 0, 1024 or 4096 bytes each. + + Include or exclude the appropriate definitions below to set the number + of tables used by this implementation. +*/ + +#if 1 /* set tables for the normal encryption round */ +#define ENC_ROUND FOUR_TABLES +#elif 0 +#define ENC_ROUND ONE_TABLE +#else +#define ENC_ROUND NO_TABLES +#endif + +#if 1 /* set tables for the last encryption round */ +#define LAST_ENC_ROUND FOUR_TABLES +#elif 0 +#define LAST_ENC_ROUND ONE_TABLE +#else +#define LAST_ENC_ROUND NO_TABLES +#endif + +#if 1 /* set tables for the normal decryption round */ +#define DEC_ROUND FOUR_TABLES +#elif 0 +#define DEC_ROUND ONE_TABLE +#else +#define DEC_ROUND NO_TABLES +#endif + +#if 1 /* set tables for the last decryption round */ +#define LAST_DEC_ROUND FOUR_TABLES +#elif 0 +#define LAST_DEC_ROUND ONE_TABLE +#else +#define LAST_DEC_ROUND NO_TABLES +#endif + +/* The decryption key schedule can be speeded up with tables in the same + way that the round functions can. Include or exclude the following + defines to set this requirement. +*/ +#if 1 +#define KEY_SCHED FOUR_TABLES +#elif 0 +#define KEY_SCHED ONE_TABLE +#else +#define KEY_SCHED NO_TABLES +#endif + +/* ---- END OF USER CONFIGURED OPTIONS ---- */ + +/* VIA ACE support is only available for VC++ and GCC */ + +#if !defined(_MSC_VER) && !defined(__GNUC__) +#if defined(ASSUME_VIA_ACE_PRESENT) +#undef ASSUME_VIA_ACE_PRESENT +#endif +#if defined(USE_VIA_ACE_IF_PRESENT) +#undef USE_VIA_ACE_IF_PRESENT +#endif +#endif + +#if defined(ASSUME_VIA_ACE_PRESENT) && !defined(USE_VIA_ACE_IF_PRESENT) +#define USE_VIA_ACE_IF_PRESENT +#endif + +/* define to reverse decryption key schedule */ +#if 1 || defined(USE_VIA_ACE_IF_PRESENT) && !defined(AES_REV_DKS) +#define AES_REV_DKS +#endif + +/* Intel AESNI uses a decryption key schedule in the encryption order */ +#if defined(USE_INTEL_AES_IF_PRESENT) && defined(AES_REV_DKS) +#undef AES_REV_DKS +#endif + +/* Assembler support requires the use of platform byte order */ + +#if(defined(ASM_X86_V1C) || defined(ASM_X86_V2C) || defined(ASM_AMD64_C)) && \ + (ALGORITHM_BYTE_ORDER != PLATFORM_BYTE_ORDER) +#undef ALGORITHM_BYTE_ORDER +#define ALGORITHM_BYTE_ORDER PLATFORM_BYTE_ORDER +#endif + +/* In this implementation the columns of the state array are each held in + 32-bit words. The state array can be held in various ways: in an array + of words, in a number of individual word variables or in a number of + processor registers. The following define maps a variable name x and + a column number c to the way the state array variable is to be held. + The first define below maps the state into an array x[c] whereas the + second form maps the state into a number of individual variables x0, + x1, etc. Another form could map individual state colums to machine + register names. +*/ + +#if defined(ARRAYS) +#define s(x, c) x[c] +#else +#define s(x, c) x##c +#endif + +/* This implementation provides subroutines for encryption, decryption + and for setting the three key lengths (separately) for encryption + and decryption. Since not all functions are needed, masks are set + up here to determine which will be implemented in C +*/ + +#if !defined(AES_ENCRYPT) +#define EFUNCS_IN_C 0 +#elif defined(ASSUME_VIA_ACE_PRESENT) || defined(ASM_X86_V1C) || defined(ASM_X86_V2C) || \ + defined(ASM_AMD64_C) +#define EFUNCS_IN_C ENC_KEYING_IN_C +#elif !defined(ASM_X86_V2) +#define EFUNCS_IN_C (ENCRYPTION_IN_C | ENC_KEYING_IN_C) +#else +#define EFUNCS_IN_C 0 +#endif + +#if !defined(AES_DECRYPT) +#define DFUNCS_IN_C 0 +#elif defined(ASSUME_VIA_ACE_PRESENT) || defined(ASM_X86_V1C) || defined(ASM_X86_V2C) || \ + defined(ASM_AMD64_C) +#define DFUNCS_IN_C DEC_KEYING_IN_C +#elif !defined(ASM_X86_V2) +#define DFUNCS_IN_C (DECRYPTION_IN_C | DEC_KEYING_IN_C) +#else +#define DFUNCS_IN_C 0 +#endif + +#define FUNCS_IN_C (EFUNCS_IN_C | DFUNCS_IN_C) + +/* END OF CONFIGURATION OPTIONS */ + +#define RC_LENGTH (5 * (AES_BLOCK_SIZE / 4 - 2)) + +/* Disable or report errors on some combinations of options */ + +#if ENC_ROUND == NO_TABLES && LAST_ENC_ROUND != NO_TABLES +#undef LAST_ENC_ROUND +#define LAST_ENC_ROUND NO_TABLES +#elif ENC_ROUND == ONE_TABLE && LAST_ENC_ROUND == FOUR_TABLES +#undef LAST_ENC_ROUND +#define LAST_ENC_ROUND ONE_TABLE +#endif + +#if ENC_ROUND == NO_TABLES && ENC_UNROLL != NONE +#undef ENC_UNROLL +#define ENC_UNROLL NONE +#endif + +#if DEC_ROUND == NO_TABLES && LAST_DEC_ROUND != NO_TABLES +#undef LAST_DEC_ROUND +#define LAST_DEC_ROUND NO_TABLES +#elif DEC_ROUND == ONE_TABLE && LAST_DEC_ROUND == FOUR_TABLES +#undef LAST_DEC_ROUND +#define LAST_DEC_ROUND ONE_TABLE +#endif + +#if DEC_ROUND == NO_TABLES && DEC_UNROLL != NONE +#undef DEC_UNROLL +#define DEC_UNROLL NONE +#endif + +#if defined(bswap32) +#define aes_sw32 bswap32 +#elif defined(bswap_32) +#define aes_sw32 bswap_32 +#else +#define brot(x, n) (((uint32_t)(x) << n) | ((uint32_t)(x) >> (32 - n))) +#define aes_sw32(x) ((brot((x), 8) & 0x00ff00ff) | (brot((x), 24) & 0xff00ff00)) +#endif + +/* upr(x,n): rotates bytes within words by n positions, moving bytes to + higher index positions with wrap around into low positions + ups(x,n): moves bytes by n positions to higher index positions in + words but without wrap around + bval(x,n): extracts a byte from a word + + WARNING: The definitions given here are intended only for use with + unsigned variables and with shift counts that are compile + time constants +*/ + +#if(ALGORITHM_BYTE_ORDER == IS_LITTLE_ENDIAN) +#define upr(x, n) (((uint32_t)(x) << (8 * (n))) | ((uint32_t)(x) >> (32 - 8 * (n)))) +#define ups(x, n) ((uint32_t)(x) << (8 * (n))) +#define bval(x, n) to_byte((x) >> (8 * (n))) +#define bytes2word(b0, b1, b2, b3) \ + (((uint32_t)(b3) << 24) | ((uint32_t)(b2) << 16) | ((uint32_t)(b1) << 8) | (b0)) +#endif + +#if(ALGORITHM_BYTE_ORDER == IS_BIG_ENDIAN) +#define upr(x, n) (((uint32_t)(x) >> (8 * (n))) | ((uint32_t)(x) << (32 - 8 * (n)))) +#define ups(x, n) ((uint32_t)(x) >> (8 * (n))) +#define bval(x, n) to_byte((x) >> (24 - 8 * (n))) +#define bytes2word(b0, b1, b2, b3) \ + (((uint32_t)(b0) << 24) | ((uint32_t)(b1) << 16) | ((uint32_t)(b2) << 8) | (b3)) +#endif + +#if defined(SAFE_IO) +#define word_in(x, c) \ + bytes2word( \ + ((const uint8_t*)(x) + 4 * c)[0], \ + ((const uint8_t*)(x) + 4 * c)[1], \ + ((const uint8_t*)(x) + 4 * c)[2], \ + ((const uint8_t*)(x) + 4 * c)[3]) +#define word_out(x, c, v) \ + { \ + ((uint8_t*)(x) + 4 * c)[0] = bval(v, 0); \ + ((uint8_t*)(x) + 4 * c)[1] = bval(v, 1); \ + ((uint8_t*)(x) + 4 * c)[2] = bval(v, 2); \ + ((uint8_t*)(x) + 4 * c)[3] = bval(v, 3); \ + } +#elif(ALGORITHM_BYTE_ORDER == PLATFORM_BYTE_ORDER) +#define word_in(x, c) (*((uint32_t*)(x) + (c))) +#define word_out(x, c, v) (*((uint32_t*)(x) + (c)) = (v)) +#else +#define word_in(x, c) aes_sw32(*((uint32_t*)(x) + (c))) +#define word_out(x, c, v) (*((uint32_t*)(x) + (c)) = aes_sw32(v)) +#endif + +/* the finite field modular polynomial and elements */ + +#define WPOLY 0x011b +#define BPOLY 0x1b + +/* multiply four bytes in GF(2^8) by 'x' {02} in parallel */ + +#define gf_c1 0x80808080 +#define gf_c2 0x7f7f7f7f +#define gf_mulx(x) ((((x)&gf_c2) << 1) ^ ((((x)&gf_c1) >> 7) * BPOLY)) + +/* The following defines provide alternative definitions of gf_mulx that might + give improved performance if a fast 32-bit multiply is not available. Note + that a temporary variable u needs to be defined where gf_mulx is used. + +#define gf_mulx(x) (u = (x) & gf_c1, u |= (u >> 1), ((x) & gf_c2) << 1) ^ ((u >> 3) | (u >> 6)) +#define gf_c4 (0x01010101 * BPOLY) +#define gf_mulx(x) (u = (x) & gf_c1, ((x) & gf_c2) << 1) ^ ((u - (u >> 7)) & gf_c4) +*/ + +/* Work out which tables are needed for the different options */ + +#if defined(ASM_X86_V1C) +#if defined(ENC_ROUND) +#undef ENC_ROUND +#endif +#define ENC_ROUND FOUR_TABLES +#if defined(LAST_ENC_ROUND) +#undef LAST_ENC_ROUND +#endif +#define LAST_ENC_ROUND FOUR_TABLES +#if defined(DEC_ROUND) +#undef DEC_ROUND +#endif +#define DEC_ROUND FOUR_TABLES +#if defined(LAST_DEC_ROUND) +#undef LAST_DEC_ROUND +#endif +#define LAST_DEC_ROUND FOUR_TABLES +#if defined(KEY_SCHED) +#undef KEY_SCHED +#define KEY_SCHED FOUR_TABLES +#endif +#endif + +#if(FUNCS_IN_C & ENCRYPTION_IN_C) || defined(ASM_X86_V1C) +#if ENC_ROUND == ONE_TABLE +#define FT1_SET +#elif ENC_ROUND == FOUR_TABLES +#define FT4_SET +#else +#define SBX_SET +#endif +#if LAST_ENC_ROUND == ONE_TABLE +#define FL1_SET +#elif LAST_ENC_ROUND == FOUR_TABLES +#define FL4_SET +#elif !defined(SBX_SET) +#define SBX_SET +#endif +#endif + +#if(FUNCS_IN_C & DECRYPTION_IN_C) || defined(ASM_X86_V1C) +#if DEC_ROUND == ONE_TABLE +#define IT1_SET +#elif DEC_ROUND == FOUR_TABLES +#define IT4_SET +#else +#define ISB_SET +#endif +#if LAST_DEC_ROUND == ONE_TABLE +#define IL1_SET +#elif LAST_DEC_ROUND == FOUR_TABLES +#define IL4_SET +#elif !defined(ISB_SET) +#define ISB_SET +#endif +#endif + +#if !(defined(REDUCE_CODE_SIZE) && (defined(ASM_X86_V2) || defined(ASM_X86_V2C))) +#if((FUNCS_IN_C & ENC_KEYING_IN_C) || (FUNCS_IN_C & DEC_KEYING_IN_C)) +#if KEY_SCHED == ONE_TABLE +#if !defined(FL1_SET) && !defined(FL4_SET) +#define LS1_SET +#endif +#elif KEY_SCHED == FOUR_TABLES +#if !defined(FL4_SET) +#define LS4_SET +#endif +#elif !defined(SBX_SET) +#define SBX_SET +#endif +#endif +#if(FUNCS_IN_C & DEC_KEYING_IN_C) +#if KEY_SCHED == ONE_TABLE +#define IM1_SET +#elif KEY_SCHED == FOUR_TABLES +#define IM4_SET +#elif !defined(SBX_SET) +#define SBX_SET +#endif +#endif +#endif + +/* generic definitions of Rijndael macros that use tables */ + +#define no_table(x, box, vf, rf, c) \ + bytes2word( \ + box[bval(vf(x, 0, c), rf(0, c))], \ + box[bval(vf(x, 1, c), rf(1, c))], \ + box[bval(vf(x, 2, c), rf(2, c))], \ + box[bval(vf(x, 3, c), rf(3, c))]) + +#define one_table(x, op, tab, vf, rf, c) \ + (tab[bval(vf(x, 0, c), rf(0, c))] ^ op(tab[bval(vf(x, 1, c), rf(1, c))], 1) ^ \ + op(tab[bval(vf(x, 2, c), rf(2, c))], 2) ^ op(tab[bval(vf(x, 3, c), rf(3, c))], 3)) + +#define four_tables(x, tab, vf, rf, c) \ + (tab[0][bval(vf(x, 0, c), rf(0, c))] ^ tab[1][bval(vf(x, 1, c), rf(1, c))] ^ \ + tab[2][bval(vf(x, 2, c), rf(2, c))] ^ tab[3][bval(vf(x, 3, c), rf(3, c))]) + +#define vf1(x, r, c) (x) +#define rf1(r, c) (r) +#define rf2(r, c) ((8 + r - c) & 3) + +/* perform forward and inverse column mix operation on four bytes in long word x in */ +/* parallel. NOTE: x must be a simple variable, NOT an expression in these macros. */ + +#if !(defined(REDUCE_CODE_SIZE) && (defined(ASM_X86_V2) || defined(ASM_X86_V2C))) + +#if defined(FM4_SET) /* not currently used */ +#define fwd_mcol(x) four_tables(x, t_use(f, m), vf1, rf1, 0) +#elif defined(FM1_SET) /* not currently used */ +#define fwd_mcol(x) one_table(x, upr, t_use(f, m), vf1, rf1, 0) +#else +#define dec_fmvars uint32_t g2 +#define fwd_mcol(x) (g2 = gf_mulx(x), g2 ^ upr((x) ^ g2, 3) ^ upr((x), 2) ^ upr((x), 1)) +#endif + +#if defined(IM4_SET) +#define inv_mcol(x) four_tables(x, t_use(i, m), vf1, rf1, 0) +#elif defined(IM1_SET) +#define inv_mcol(x) one_table(x, upr, t_use(i, m), vf1, rf1, 0) +#else +#define dec_imvars uint32_t g2, g4, g9 +#define inv_mcol(x) \ + (g2 = gf_mulx(x), \ + g4 = gf_mulx(g2), \ + g9 = (x) ^ gf_mulx(g4), \ + g4 ^= g9, \ + (x) ^ g2 ^ g4 ^ upr(g2 ^ g9, 3) ^ upr(g4, 2) ^ upr(g9, 1)) +#endif + +#if defined(FL4_SET) +#define ls_box(x, c) four_tables(x, t_use(f, l), vf1, rf2, c) +#elif defined(LS4_SET) +#define ls_box(x, c) four_tables(x, t_use(l, s), vf1, rf2, c) +#elif defined(FL1_SET) +#define ls_box(x, c) one_table(x, upr, t_use(f, l), vf1, rf2, c) +#elif defined(LS1_SET) +#define ls_box(x, c) one_table(x, upr, t_use(l, s), vf1, rf2, c) +#else +#define ls_box(x, c) no_table(x, t_use(s, box), vf1, rf2, c) +#endif + +#endif + +#if defined(ASM_X86_V1C) && defined(AES_DECRYPT) && !defined(ISB_SET) +#define ISB_SET +#endif + +#endif diff --git a/applications/external/flipbip/lib/crypto/aes/aestab.c b/applications/external/flipbip/lib/crypto/aes/aestab.c new file mode 100644 index 000000000..0bfb7808f --- /dev/null +++ b/applications/external/flipbip/lib/crypto/aes/aestab.c @@ -0,0 +1,403 @@ +/* +--------------------------------------------------------------------------- +Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. + +The redistribution and use of this software (with or without changes) +is allowed without the payment of fees or royalties provided that: + + source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation. + +This software is provided 'as is' with no explicit or implied warranties +in respect of its operation, including, but not limited to, correctness +and fitness for purpose. +--------------------------------------------------------------------------- +Issue Date: 20/12/2007 +*/ + +#define DO_TABLES + +#include "aes.h" +#include "aesopt.h" + +#if defined(STATIC_TABLES) + +#define sb_data(w) \ + { \ + w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5), w(0x30), w(0x01), \ + w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), w(0x76), w(0xca), w(0x82), w(0xc9), \ + w(0x7d), w(0xfa), w(0x59), w(0x47), w(0xf0), w(0xad), w(0xd4), w(0xa2), w(0xaf), \ + w(0x9c), w(0xa4), w(0x72), w(0xc0), w(0xb7), w(0xfd), w(0x93), w(0x26), w(0x36), \ + w(0x3f), w(0xf7), w(0xcc), w(0x34), w(0xa5), w(0xe5), w(0xf1), w(0x71), w(0xd8), \ + w(0x31), w(0x15), w(0x04), w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), \ + w(0x9a), w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75), \ + w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), w(0xa0), w(0x52), \ + w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), w(0x2f), w(0x84), w(0x53), w(0xd1), \ + w(0x00), w(0xed), w(0x20), w(0xfc), w(0xb1), w(0x5b), w(0x6a), w(0xcb), w(0xbe), \ + w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf), w(0xd0), w(0xef), w(0xaa), w(0xfb), \ + w(0x43), w(0x4d), w(0x33), w(0x85), w(0x45), w(0xf9), w(0x02), w(0x7f), w(0x50), \ + w(0x3c), w(0x9f), w(0xa8), w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), \ + w(0x38), w(0xf5), w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), \ + w(0xd2), w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), w(0x44), w(0x17), \ + w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), w(0x5d), w(0x19), w(0x73), w(0x60), \ + w(0x81), w(0x4f), w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88), w(0x46), w(0xee), \ + w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb), w(0xe0), w(0x32), w(0x3a), \ + w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c), w(0xc2), w(0xd3), w(0xac), w(0x62), \ + w(0x91), w(0x95), w(0xe4), w(0x79), w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), \ + w(0xd5), w(0x4e), w(0xa9), w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), \ + w(0xae), w(0x08), w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), w(0xa6), w(0xb4), \ + w(0xc6), w(0xe8), w(0xdd), w(0x74), w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a), \ + w(0x70), w(0x3e), w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e), w(0x61), \ + w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e), w(0xe1), w(0xf8), \ + w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94), w(0x9b), w(0x1e), w(0x87), \ + w(0xe9), w(0xce), w(0x55), w(0x28), w(0xdf), w(0x8c), w(0xa1), w(0x89), w(0x0d), \ + w(0xbf), w(0xe6), w(0x42), w(0x68), w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), \ + w(0x54), w(0xbb), w(0x16) \ + } + +#define isb_data(w) \ + { \ + w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38), w(0xbf), w(0x40), \ + w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), w(0xfb), w(0x7c), w(0xe3), w(0x39), \ + w(0x82), w(0x9b), w(0x2f), w(0xff), w(0x87), w(0x34), w(0x8e), w(0x43), w(0x44), \ + w(0xc4), w(0xde), w(0xe9), w(0xcb), w(0x54), w(0x7b), w(0x94), w(0x32), w(0xa6), \ + w(0xc2), w(0x23), w(0x3d), w(0xee), w(0x4c), w(0x95), w(0x0b), w(0x42), w(0xfa), \ + w(0xc3), w(0x4e), w(0x08), w(0x2e), w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), \ + w(0xb2), w(0x76), w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25), \ + w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), w(0x16), w(0xd4), \ + w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), w(0xb6), w(0x92), w(0x6c), w(0x70), \ + w(0x48), w(0x50), w(0xfd), w(0xed), w(0xb9), w(0xda), w(0x5e), w(0x15), w(0x46), \ + w(0x57), w(0xa7), w(0x8d), w(0x9d), w(0x84), w(0x90), w(0xd8), w(0xab), w(0x00), \ + w(0x8c), w(0xbc), w(0xd3), w(0x0a), w(0xf7), w(0xe4), w(0x58), w(0x05), w(0xb8), \ + w(0xb3), w(0x45), w(0x06), w(0xd0), w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), \ + w(0x0f), w(0x02), w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), \ + w(0x6b), w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), w(0xdc), w(0xea), \ + w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), w(0xb4), w(0xe6), w(0x73), w(0x96), \ + w(0xac), w(0x74), w(0x22), w(0xe7), w(0xad), w(0x35), w(0x85), w(0xe2), w(0xf9), \ + w(0x37), w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e), w(0x47), w(0xf1), w(0x1a), \ + w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89), w(0x6f), w(0xb7), w(0x62), w(0x0e), \ + w(0xaa), w(0x18), w(0xbe), w(0x1b), w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), \ + w(0xd2), w(0x79), w(0x20), w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), \ + w(0x5a), w(0xf4), w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), w(0x07), w(0xc7), \ + w(0x31), w(0xb1), w(0x12), w(0x10), w(0x59), w(0x27), w(0x80), w(0xec), w(0x5f), \ + w(0x60), w(0x51), w(0x7f), w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d), w(0x2d), \ + w(0xe5), w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef), w(0xa0), w(0xe0), \ + w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0), w(0xc8), w(0xeb), w(0xbb), \ + w(0x3c), w(0x83), w(0x53), w(0x99), w(0x61), w(0x17), w(0x2b), w(0x04), w(0x7e), \ + w(0xba), w(0x77), w(0xd6), w(0x26), w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), \ + w(0x21), w(0x0c), w(0x7d) \ + } + +#define mm_data(w) \ + { \ + w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07), w(0x08), w(0x09), \ + w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), w(0x0f), w(0x10), w(0x11), w(0x12), \ + w(0x13), w(0x14), w(0x15), w(0x16), w(0x17), w(0x18), w(0x19), w(0x1a), w(0x1b), \ + w(0x1c), w(0x1d), w(0x1e), w(0x1f), w(0x20), w(0x21), w(0x22), w(0x23), w(0x24), \ + w(0x25), w(0x26), w(0x27), w(0x28), w(0x29), w(0x2a), w(0x2b), w(0x2c), w(0x2d), \ + w(0x2e), w(0x2f), w(0x30), w(0x31), w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), \ + w(0x37), w(0x38), w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f), \ + w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), w(0x47), w(0x48), \ + w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), w(0x4e), w(0x4f), w(0x50), w(0x51), \ + w(0x52), w(0x53), w(0x54), w(0x55), w(0x56), w(0x57), w(0x58), w(0x59), w(0x5a), \ + w(0x5b), w(0x5c), w(0x5d), w(0x5e), w(0x5f), w(0x60), w(0x61), w(0x62), w(0x63), \ + w(0x64), w(0x65), w(0x66), w(0x67), w(0x68), w(0x69), w(0x6a), w(0x6b), w(0x6c), \ + w(0x6d), w(0x6e), w(0x6f), w(0x70), w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), \ + w(0x76), w(0x77), w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), \ + w(0x7f), w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), w(0x86), w(0x87), \ + w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), w(0x8d), w(0x8e), w(0x8f), w(0x90), \ + w(0x91), w(0x92), w(0x93), w(0x94), w(0x95), w(0x96), w(0x97), w(0x98), w(0x99), \ + w(0x9a), w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f), w(0xa0), w(0xa1), w(0xa2), \ + w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7), w(0xa8), w(0xa9), w(0xaa), w(0xab), \ + w(0xac), w(0xad), w(0xae), w(0xaf), w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), \ + w(0xb5), w(0xb6), w(0xb7), w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), \ + w(0xbe), w(0xbf), w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), w(0xc5), w(0xc6), \ + w(0xc7), w(0xc8), w(0xc9), w(0xca), w(0xcb), w(0xcc), w(0xcd), w(0xce), w(0xcf), \ + w(0xd0), w(0xd1), w(0xd2), w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7), w(0xd8), \ + w(0xd9), w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf), w(0xe0), w(0xe1), \ + w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7), w(0xe8), w(0xe9), w(0xea), \ + w(0xeb), w(0xec), w(0xed), w(0xee), w(0xef), w(0xf0), w(0xf1), w(0xf2), w(0xf3), \ + w(0xf4), w(0xf5), w(0xf6), w(0xf7), w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), \ + w(0xfd), w(0xfe), w(0xff) \ + } + +#define rc_data(w) \ + { w(0x01), w(0x02), w(0x04), w(0x08), w(0x10), w(0x20), w(0x40), w(0x80), w(0x1b), w(0x36) } + +#define h0(x) (x) + +#define w0(p) bytes2word(p, 0, 0, 0) +#define w1(p) bytes2word(0, p, 0, 0) +#define w2(p) bytes2word(0, 0, p, 0) +#define w3(p) bytes2word(0, 0, 0, p) + +#define u0(p) bytes2word(f2(p), p, p, f3(p)) +#define u1(p) bytes2word(f3(p), f2(p), p, p) +#define u2(p) bytes2word(p, f3(p), f2(p), p) +#define u3(p) bytes2word(p, p, f3(p), f2(p)) + +#define v0(p) bytes2word(fe(p), f9(p), fd(p), fb(p)) +#define v1(p) bytes2word(fb(p), fe(p), f9(p), fd(p)) +#define v2(p) bytes2word(fd(p), fb(p), fe(p), f9(p)) +#define v3(p) bytes2word(f9(p), fd(p), fb(p), fe(p)) + +#endif + +#if defined(STATIC_TABLES) || !defined(FF_TABLES) + +#define f2(x) ((x << 1) ^ (((x >> 7) & 1) * WPOLY)) +#define f4(x) ((x << 2) ^ (((x >> 6) & 1) * WPOLY) ^ (((x >> 6) & 2) * WPOLY)) +#define f8(x) \ + ((x << 3) ^ (((x >> 5) & 1) * WPOLY) ^ (((x >> 5) & 2) * WPOLY) ^ (((x >> 5) & 4) * WPOLY)) +#define f3(x) (f2(x) ^ x) +#define f9(x) (f8(x) ^ x) +#define fb(x) (f8(x) ^ f2(x) ^ x) +#define fd(x) (f8(x) ^ f4(x) ^ x) +#define fe(x) (f8(x) ^ f4(x) ^ f2(x)) + +#else + +#define f2(x) ((x) ? pow[log[x] + 0x19] : 0) +#define f3(x) ((x) ? pow[log[x] + 0x01] : 0) +#define f9(x) ((x) ? pow[log[x] + 0xc7] : 0) +#define fb(x) ((x) ? pow[log[x] + 0x68] : 0) +#define fd(x) ((x) ? pow[log[x] + 0xee] : 0) +#define fe(x) ((x) ? pow[log[x] + 0xdf] : 0) + +#endif + +#include "aestab.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +#if defined(STATIC_TABLES) + +/* implemented in case of wrong call for fixed tables */ + +AES_RETURN aes_init(void) { + return EXIT_SUCCESS; +} + +#else /* Generate the tables for the dynamic table option */ + +#if defined(FF_TABLES) + +#define gf_inv(x) ((x) ? pow[255 - log[x]] : 0) + +#else + +/* It will generally be sensible to use tables to compute finite + field multiplies and inverses but where memory is scarse this + code might sometimes be better. But it only has effect during + initialisation so its pretty unimportant in overall terms. +*/ + +/* return 2 ^ (n - 1) where n is the bit number of the highest bit + set in x with x in the range 1 < x < 0x00000200. This form is + used so that locals within fi can be bytes rather than words +*/ + +static uint8_t hibit(const uint32_t x) { + uint8_t r = (uint8_t)((x >> 1) | (x >> 2)); + + r |= (r >> 2); + r |= (r >> 4); + return (r + 1) >> 1; +} + +/* return the inverse of the finite field element x */ + +static uint8_t gf_inv(const uint8_t x) { + uint8_t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0; + + if(x < 2) return x; + + for(;;) { + if(n1) + while(n2 >= n1) /* divide polynomial p2 by p1 */ + { + n2 /= n1; /* shift smaller polynomial left */ + p2 ^= (p1 * n2) & 0xff; /* and remove from larger one */ + v2 ^= v1 * n2; /* shift accumulated value and */ + n2 = hibit(p2); /* add into result */ + } + else + return v1; + + if(n2) /* repeat with values swapped */ + while(n1 >= n2) { + n1 /= n2; + p1 ^= p2 * n1; + v1 ^= v2 * n1; + n1 = hibit(p1); + } + else + return v2; + } +} + +#endif + +/* The forward and inverse affine transformations used in the S-box */ +uint8_t fwd_affine(const uint8_t x) { + uint32_t w = x; + w ^= (w << 1) ^ (w << 2) ^ (w << 3) ^ (w << 4); + return 0x63 ^ ((w ^ (w >> 8)) & 0xff); +} + +uint8_t inv_affine(const uint8_t x) { + uint32_t w = x; + w = (w << 1) ^ (w << 3) ^ (w << 6); + return 0x05 ^ ((w ^ (w >> 8)) & 0xff); +} + +static int init = 0; + +AES_RETURN aes_init(void) { + uint32_t i, w; + +#if defined(FF_TABLES) + + uint8_t pow[512] = {0}, log[256] = {0}; + + if(init) return EXIT_SUCCESS; + /* log and power tables for GF(2^8) finite field with + WPOLY as modular polynomial - the simplest primitive + root is 0x03, used here to generate the tables + */ + + i = 0; + w = 1; + do { + pow[i] = (uint8_t)w; + pow[i + 255] = (uint8_t)w; + log[w] = (uint8_t)i++; + w ^= (w << 1) ^ (w & 0x80 ? WPOLY : 0); + } while(w != 1); + +#else + if(init) return EXIT_SUCCESS; +#endif + + for(i = 0, w = 1; i < RC_LENGTH; ++i) { + t_set(r, c)[i] = bytes2word(w, 0, 0, 0); + w = f2(w); + } + + for(i = 0; i < 256; ++i) { + uint8_t b; + + b = fwd_affine(gf_inv((uint8_t)i)); + w = bytes2word(f2(b), b, b, f3(b)); + +#if defined(SBX_SET) + t_set(s, box)[i] = b; +#endif + +#if defined(FT1_SET) /* tables for a normal encryption round */ + t_set(f, n)[i] = w; +#endif +#if defined(FT4_SET) + t_set(f, n)[0][i] = w; + t_set(f, n)[1][i] = upr(w, 1); + t_set(f, n)[2][i] = upr(w, 2); + t_set(f, n)[3][i] = upr(w, 3); +#endif + w = bytes2word(b, 0, 0, 0); + +#if defined(FL1_SET) /* tables for last encryption round (may also */ + t_set(f, l)[i] = w; /* be used in the key schedule) */ +#endif +#if defined(FL4_SET) + t_set(f, l)[0][i] = w; + t_set(f, l)[1][i] = upr(w, 1); + t_set(f, l)[2][i] = upr(w, 2); + t_set(f, l)[3][i] = upr(w, 3); +#endif + +#if defined(LS1_SET) /* table for key schedule if t_set(f,l) above is*/ + t_set(l, s)[i] = w; /* not of the required form */ +#endif +#if defined(LS4_SET) + t_set(l, s)[0][i] = w; + t_set(l, s)[1][i] = upr(w, 1); + t_set(l, s)[2][i] = upr(w, 2); + t_set(l, s)[3][i] = upr(w, 3); +#endif + + b = gf_inv(inv_affine((uint8_t)i)); + w = bytes2word(fe(b), f9(b), fd(b), fb(b)); + +#if defined(IM1_SET) /* tables for the inverse mix column operation */ + t_set(i, m)[b] = w; +#endif +#if defined(IM4_SET) + t_set(i, m)[0][b] = w; + t_set(i, m)[1][b] = upr(w, 1); + t_set(i, m)[2][b] = upr(w, 2); + t_set(i, m)[3][b] = upr(w, 3); +#endif + +#if defined(ISB_SET) + t_set(i, box)[i] = b; +#endif +#if defined(IT1_SET) /* tables for a normal decryption round */ + t_set(i, n)[i] = w; +#endif +#if defined(IT4_SET) + t_set(i, n)[0][i] = w; + t_set(i, n)[1][i] = upr(w, 1); + t_set(i, n)[2][i] = upr(w, 2); + t_set(i, n)[3][i] = upr(w, 3); +#endif + w = bytes2word(b, 0, 0, 0); +#if defined(IL1_SET) /* tables for last decryption round */ + t_set(i, l)[i] = w; +#endif +#if defined(IL4_SET) + t_set(i, l)[0][i] = w; + t_set(i, l)[1][i] = upr(w, 1); + t_set(i, l)[2][i] = upr(w, 2); + t_set(i, l)[3][i] = upr(w, 3); +#endif + } + init = 1; + return EXIT_SUCCESS; +} + +/* + Automatic code initialisation (suggested by by Henrik S. Gaßmann) + based on code provided by Joe Lowe and placed in the public domain at: + http://stackoverflow.com/questions/1113409/attribute-constructor-equivalent-in-vc +*/ + +#ifdef _MSC_VER + +#pragma section(".CRT$XCU", read) + +__declspec(allocate(".CRT$XCU")) void(__cdecl* aes_startup)(void) = aes_init; + +#elif defined(__GNUC__) + +static void aes_startup(void) __attribute__((constructor)); + +static void aes_startup(void) { + aes_init(); +} + +#else + +#pragma message("dynamic tables must be initialised manually on your system") + +#endif + +#endif + +#if defined(__cplusplus) +} +#endif diff --git a/applications/external/flipbip/lib/crypto/aes/aestab.h b/applications/external/flipbip/lib/crypto/aes/aestab.h new file mode 100644 index 000000000..9dfcded1a --- /dev/null +++ b/applications/external/flipbip/lib/crypto/aes/aestab.h @@ -0,0 +1,173 @@ +/* +--------------------------------------------------------------------------- +Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. + +The redistribution and use of this software (with or without changes) +is allowed without the payment of fees or royalties provided that: + + source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation. + +This software is provided 'as is' with no explicit or implied warranties +in respect of its operation, including, but not limited to, correctness +and fitness for purpose. +--------------------------------------------------------------------------- +Issue Date: 20/12/2007 + + This file contains the code for declaring the tables needed to implement + AES. The file aesopt.h is assumed to be included before this header file. + If there are no global variables, the definitions here can be used to put + the AES tables in a structure so that a pointer can then be added to the + AES context to pass them to the AES routines that need them. If this + facility is used, the calling program has to ensure that this pointer is + managed appropriately. In particular, the value of the t_dec(in,it) item + in the table structure must be set to zero in order to ensure that the + tables are initialised. In practice the three code sequences in aeskey.c + that control the calls to aes_init() and the aes_init() routine itself will + have to be changed for a specific implementation. If global variables are + available it will generally be preferable to use them with the precomputed + STATIC_TABLES option that uses static global tables. + + The following defines can be used to control the way the tables + are defined, initialised and used in embedded environments that + require special features for these purposes + + the 't_dec' construction is used to declare fixed table arrays + the 't_set' construction is used to set fixed table values + the 't_use' construction is used to access fixed table values + + 256 byte tables: + + t_xxx(s,box) => forward S box + t_xxx(i,box) => inverse S box + + 256 32-bit word OR 4 x 256 32-bit word tables: + + t_xxx(f,n) => forward normal round + t_xxx(f,l) => forward last round + t_xxx(i,n) => inverse normal round + t_xxx(i,l) => inverse last round + t_xxx(l,s) => key schedule table + t_xxx(i,m) => key schedule table + + Other variables and tables: + + t_xxx(r,c) => the rcon table +*/ + +#if !defined(_AESTAB_H) +#define _AESTAB_H + +#if defined(__cplusplus) +extern "C" { +#endif + +#define t_dec(m, n) t_##m##n +#define t_set(m, n) t_##m##n +#define t_use(m, n) t_##m##n + +#if defined(STATIC_TABLES) +#if !defined(__GNUC__) && (defined(__MSDOS__) || defined(__WIN16__)) +/* make tables far data to avoid using too much DGROUP space (PG) */ +#define CONST const far +#else +#define CONST const +#endif +#else +#define CONST +#endif + +#if defined(DO_TABLES) +#define EXTERN +#else +#define EXTERN extern +#endif + +#if defined(_MSC_VER) && defined(TABLE_ALIGN) +#define ALIGN __declspec(align(TABLE_ALIGN)) +#else +#define ALIGN +#endif + +#if defined(__WATCOMC__) && (__WATCOMC__ >= 1100) +#define XP_DIR __cdecl +#else +#define XP_DIR +#endif + +#if defined(DO_TABLES) && defined(STATIC_TABLES) +#define d_1(t, n, b, e) EXTERN ALIGN CONST XP_DIR t n[256] = b(e) +#define d_4(t, n, b, e, f, g, h) EXTERN ALIGN CONST XP_DIR t n[4][256] = {b(e), b(f), b(g), b(h)} +EXTERN ALIGN CONST uint32_t t_dec(r, c)[RC_LENGTH] = rc_data(w0); +#else +#define d_1(t, n, b, e) EXTERN ALIGN CONST XP_DIR t n[256] +#define d_4(t, n, b, e, f, g, h) EXTERN ALIGN CONST XP_DIR t n[4][256] +EXTERN ALIGN CONST uint32_t t_dec(r, c)[RC_LENGTH]; +#endif + +#if defined(SBX_SET) +d_1(uint8_t, t_dec(s, box), sb_data, h0); +#endif +#if defined(ISB_SET) +d_1(uint8_t, t_dec(i, box), isb_data, h0); +#endif + +#if defined(FT1_SET) +d_1(uint32_t, t_dec(f, n), sb_data, u0); +#endif +#if defined(FT4_SET) +d_4(uint32_t, t_dec(f, n), sb_data, u0, u1, u2, u3); +#endif + +#if defined(FL1_SET) +d_1(uint32_t, t_dec(f, l), sb_data, w0); +#endif +#if defined(FL4_SET) +d_4(uint32_t, t_dec(f, l), sb_data, w0, w1, w2, w3); +#endif + +#if defined(IT1_SET) +d_1(uint32_t, t_dec(i, n), isb_data, v0); +#endif +#if defined(IT4_SET) +d_4(uint32_t, t_dec(i, n), isb_data, v0, v1, v2, v3); +#endif + +#if defined(IL1_SET) +d_1(uint32_t, t_dec(i, l), isb_data, w0); +#endif +#if defined(IL4_SET) +d_4(uint32_t, t_dec(i, l), isb_data, w0, w1, w2, w3); +#endif + +#if defined(LS1_SET) +#if defined(FL1_SET) +#undef LS1_SET +#else +d_1(uint32_t, t_dec(l, s), sb_data, w0); +#endif +#endif + +#if defined(LS4_SET) +#if defined(FL4_SET) +#undef LS4_SET +#else +d_4(uint32_t, t_dec(l, s), sb_data, w0, w1, w2, w3); +#endif +#endif + +#if defined(IM1_SET) +d_1(uint32_t, t_dec(i, m), mm_data, v0); +#endif +#if defined(IM4_SET) +d_4(uint32_t, t_dec(i, m), mm_data, v0, v1, v2, v3); +#endif + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/applications/external/flipbip/lib/crypto/aes/aestst.c b/applications/external/flipbip/lib/crypto/aes/aestst.c new file mode 100644 index 000000000..f9d6465dd --- /dev/null +++ b/applications/external/flipbip/lib/crypto/aes/aestst.c @@ -0,0 +1,189 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved. + + LICENSE TERMS + + The redistribution and use of this software (with or without changes) + is allowed without the payment of fees or royalties provided that: + + 1. source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + 2. binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation; + + 3. the name of the copyright holder is not used to endorse products + built using this software without specific written permission. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 20/12/2007 +*/ + +// Correct Output (for variable block size - AES_BLOCK_SIZE undefined): + +// lengths: block = 16 bytes, key = 16 bytes +// key = 2b7e151628aed2a6abf7158809cf4f3c +// input = 3243f6a8885a308d313198a2e0370734 +// encrypt = 3925841d02dc09fbdc118597196a0b32 +// decrypt = 3243f6a8885a308d313198a2e0370734 + +// lengths: block = 16 bytes, key = 24 bytes +// key = 2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da5 +// input = 3243f6a8885a308d313198a2e0370734 +// encrypt = f9fb29aefc384a250340d833b87ebc00 +// decrypt = 3243f6a8885a308d313198a2e0370734 + +// lengths: block = 16 bytes, key = 32 bytes +// key = 2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da56a784d9045190cfe +// input = 3243f6a8885a308d313198a2e0370734 +// encrypt = 1a6e6c2c662e7da6501ffb62bc9e93f3 +// decrypt = 3243f6a8885a308d313198a2e0370734 + +#include +#include + +#include "aes.h" +#include "aestst.h" + +void out_state(long s0, long s1, long s2, long s3) { + printf("\n%08lx%08lx%08lx%08lx", s0, s1, s2, s3); +} + +void oblk(char m[], unsigned char v[], unsigned long n) { + unsigned long i; + + printf("\n%s", m); + + for(i = 0; i < n; ++i) printf("%02x", v[i]); +} + +void message(const char* s) { + printf("%s", s); +} + +unsigned char pih[32] = // hex digits of pi + {0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, 0x31, 0x31, 0x98, + 0xa2, 0xe0, 0x37, 0x07, 0x34, 0x4a, 0x40, 0x93, 0x82, 0x22, 0x99, + 0xf3, 0x1d, 0x00, 0x82, 0xef, 0xa9, 0x8e, 0xc4, 0xe6, 0xc8}; + +unsigned char exh[32] = // hex digits of e + {0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, + 0x88, 0x09, 0xcf, 0x4f, 0x3c, 0x76, 0x2e, 0x71, 0x60, 0xf3, 0x8b, + 0x4d, 0xa5, 0x6a, 0x78, 0x4d, 0x90, 0x45, 0x19, 0x0c, 0xfe}; + +unsigned char res[3][32] = { + {0x39, 0x25, 0x84, 0x1d, 0x02, 0xdc, 0x09, 0xfb, 0xdc, 0x11, 0x85, 0x97, 0x19, 0x6a, 0x0b, 0x32}, + {0xf9, 0xfb, 0x29, 0xae, 0xfc, 0x38, 0x4a, 0x25, 0x03, 0x40, 0xd8, 0x33, 0xb8, 0x7e, 0xbc, 0x00}, + {0x1a, 0x6e, 0x6c, 0x2c, 0x66, 0x2e, 0x7d, 0xa6, 0x50, 0x1f, 0xfb, 0x62, 0xbc, 0x9e, 0x93, 0xf3}}; + +// void cycles(volatile uint64_t *rtn) +// { +// #if defined( _MSCVER ) +// __asm // read the Pentium Time Stamp Counter +// { cpuid +// rdtsc +// mov ecx,rtn +// mov [ecx],eax +// mov [ecx+4],edx +// cpuid +// } +// #elif defined( __GNUC__ ) +// #if defined(__aarch64__) +// __asm__ __volatile__("mrs %0, cntvct_el0": "=r" (*rtn)); +// #else +// __asm__ __volatile__("rdtsc": "=A" (*rtn)); +// #endif +// #endif +// } + +int main(void) { + unsigned char out[32], ret[32], err = 0; + f_ectx alge[1]; + f_dctx algd[1]; + + aes_init(); + + message("\nRun tests for the AES algorithm"); + + memset(&alge, 0, sizeof(aes_encrypt_ctx)); + memset(&algd, 0, sizeof(aes_decrypt_ctx)); + +#if defined(AES_128) + memset(out, 0xcc, 16); + memset(ret, 0xcc, 16); + printf("\n\n// lengths: block = 16, bytes, key = 16 bytes"); + f_enc_key128(alge, exh); + oblk("// key = ", exh, 16); + oblk("// input = ", pih, 16); + do_enc(alge, pih, out, 1); + oblk("// encrypt = ", out, 16); + if(memcmp(out, res[0], 16)) { + message(" error"); + err += 1; + } + f_dec_key128(algd, exh); + do_dec(algd, out, ret, 1); + oblk("// decrypt = ", ret, 16); + if(memcmp(ret, pih, 16)) { + message(" error"); + err += 2; + } +#endif + +#if defined(AES_192) + memset(out, 0xcc, 16); + memset(ret, 0xcc, 16); + printf("\n\n// lengths: block = 16, bytes, key = 24 bytes"); + f_enc_key192(alge, exh); + oblk("// key = ", exh, 24); + oblk("// input = ", pih, 16); + do_enc(alge, pih, out, 1); + oblk("// encrypt = ", out, 16); + if(memcmp(out, res[1], 16)) { + message(" error"); + err += 4; + } + f_dec_key192(algd, exh); + do_dec(algd, out, ret, 1); + oblk("// decrypt = ", ret, 16); + if(memcmp(ret, pih, 16)) { + message(" error"); + err += 8; + } +#endif + +#if defined(AES_256) + memset(out, 0xcc, 16); + memset(ret, 0xcc, 16); + printf("\n\n// lengths: block = 16, bytes, key = 32 bytes"); + f_enc_key256(alge, exh); + oblk("// key = ", exh, 32); + oblk("// input = ", pih, 16); + do_enc(alge, pih, out, 1); + oblk("// encrypt = ", out, 16); + if(memcmp(out, res[2], 16)) { + message(" error"); + err += 16; + } + f_dec_key256(algd, exh); + do_dec(algd, out, ret, 1); + oblk("// decrypt = ", ret, 16); + if(memcmp(ret, pih, 16)) { + message(" error"); + err += 32; + } +#endif + + if(!err) + message("\n\nThese values are all correct\n\n"); + else + message("\n\nSome values are in error\n\n"); + + return 0; +} diff --git a/applications/external/flipbip/lib/crypto/aes/aestst.h b/applications/external/flipbip/lib/crypto/aes/aestst.h new file mode 100644 index 000000000..bb38b0434 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/aes/aestst.h @@ -0,0 +1,85 @@ +/* +--------------------------------------------------------------------------- +Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. + +The redistribution and use of this software (with or without changes) +is allowed without the payment of fees or royalties provided that: + + source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation. + +This software is provided 'as is' with no explicit or implied warranties +in respect of its operation, including, but not limited to, correctness +and fitness for purpose. +--------------------------------------------------------------------------- +Issue Date: 20/12/2007 +*/ + +// The following definitions are required for testing only, They are not needed +// for AES (Rijndael) implementation. They are used to allow C, C++ and DLL +// data access and subroutine calls to be expressed in the same form in the +// testing code. + +#ifndef AESTST_H +#define AESTST_H + +#define f_info(x) (x)->inf.b[2] +#define f_ectx aes_encrypt_ctx +#define f_enc_key128(a, b) aes_encrypt_key128((b), (a)) +#define f_enc_key192(a, b) aes_encrypt_key192((b), (a)) +#define f_enc_key256(a, b) aes_encrypt_key256((b), (a)) +#define f_enc_key(a, b, c) aes_encrypt_key((b), (c), (a)) +#define f_enc_blk(a, b, c) aes_encrypt((b), (c), (a)) + +#define f_dctx aes_decrypt_ctx +#define f_dec_key128(a, b) aes_decrypt_key128((b), (a)) +#define f_dec_key192(a, b) aes_decrypt_key192((b), (a)) +#define f_dec_key256(a, b) aes_decrypt_key256((b), (a)) +#define f_dec_key(a, b, c) aes_decrypt_key((b), (c), (a)) +#define f_dec_blk(a, b, c) aes_decrypt((b), (c), (a)) + +#define f_talign(a, b) aes_test_alignment_detection(b) +#define f_mode_reset(a) aes_mode_reset(a) +#define f_ecb_enc(a, b, c, d) aes_ecb_encrypt((b), (c), (d), (a)) +#define f_ecb_dec(a, b, c, d) aes_ecb_decrypt((b), (c), (d), (a)) +#define f_cbc_enc(a, b, c, d, e) aes_cbc_encrypt((b), (c), (d), (e), (a)) +#define f_cbc_dec(a, b, c, d, e) aes_cbc_decrypt((b), (c), (d), (e), (a)) +#define f_cfb_enc(a, b, c, d, e) aes_cfb_encrypt((b), (c), (d), (e), (a)) +#define f_cfb_dec(a, b, c, d, e) aes_cfb_decrypt((b), (c), (d), (e), (a)) +#define f_ofb_cry(a, b, c, d, e) aes_ofb_crypt((b), (c), (d), (e), (a)) +#define f_ctr_cry(a, b, c, d, e, f) aes_ctr_crypt((b), (c), (d), (e), (f), (a)) + +#define ek_name128 "aes_encrypt_key128" +#define ek_name192 "aes_encrypt_key192" +#define ek_name256 "aes_encrypt_key256" +#define ek_name "aes_encrypt_key" +#define eb_name "aes_encrypt" + +#define dk_name128 "aes_decrypt_key128" +#define dk_name192 "aes_decrypt_key192" +#define dk_name256 "aes_decrypt_key256" +#define dk_name "aes_decrypt_key" +#define db_name "aes_decrypt" + +#define eres_name "aes_mode_reset" +#define ecbe_name "aes_ecb_encrypt" +#define ecbd_name "aes_ecb_decrypt" +#define cbce_name "aes_cbc_encrypt" +#define cbcd_name "aes_cbc_decrypt" +#define cfbe_name "aes_cfb_encrypt" +#define cfbd_name "aes_cfb_decrypt" +#define ofb_name "aes_ofb_crypt" +#define ctr_name "aes_ctr_crypt" + +#ifndef AES_N_BLOCK +#define do_enc(a, b, c, d) f_enc_blk(a, b, c) +#define do_dec(a, b, c, d) f_dec_blk(a, b, c) +#else +#define do_enc(a, b, c, d) f_ecb_enc(a, b, c, 1) +#define do_dec(a, b, c, d) f_ecb_dec(a, b, c, 1) +#endif + +#endif diff --git a/applications/external/flipbip/lib/crypto/base32.c b/applications/external/flipbip/lib/crypto/base32.c new file mode 100644 index 000000000..e211bb308 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/base32.c @@ -0,0 +1,241 @@ +/** + * Copyright (c) 2017 Saleem Rashid + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, E1PRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "base32.h" + +#include + +const char* BASE32_ALPHABET_RFC4648 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ23456789"; + +static inline void base32_5to8(const uint8_t* in, uint8_t length, uint8_t* out); +static inline bool + base32_8to5(const uint8_t* in, uint8_t length, uint8_t* out, const char* alphabet); +static inline void base32_8to5_raw(const uint8_t* in, uint8_t length, uint8_t* out); + +static inline int base32_encode_character(uint8_t decoded, const char* alphabet); +static inline int base32_decode_character(char encoded, const char* alphabet); + +char* base32_encode( + const uint8_t* in, + size_t inlen, + char* out, + size_t outlen, + const char* alphabet) { + size_t length = base32_encoded_length(inlen); + if(outlen <= length) { + return NULL; + } + + base32_encode_unsafe(in, inlen, (uint8_t*)out); + + for(size_t i = 0; i < length; i++) { + int ret = base32_encode_character(out[i], alphabet); + + if(ret == -1) { + return false; + } else { + out[i] = ret; + } + } + + out[length] = '\0'; + return &out[length]; +} + +uint8_t* + base32_decode(const char* in, size_t inlen, uint8_t* out, size_t outlen, const char* alphabet) { + size_t length = base32_decoded_length(inlen); + if(outlen < length) { + return NULL; + } + + if(!base32_decode_unsafe((uint8_t*)in, inlen, (uint8_t*)out, alphabet)) { + return NULL; + } + + return &out[length]; +} + +void base32_encode_unsafe(const uint8_t* in, size_t inlen, uint8_t* out) { + uint8_t remainder = inlen % 5; + size_t limit = inlen - remainder; + + size_t i = 0, j = 0; + for(i = 0, j = 0; i < limit; i += 5, j += 8) { + base32_5to8(&in[i], 5, &out[j]); + } + + if(remainder) base32_5to8(&in[i], remainder, &out[j]); +} + +bool base32_decode_unsafe(const uint8_t* in, size_t inlen, uint8_t* out, const char* alphabet) { + uint8_t remainder = inlen % 8; + size_t limit = inlen - remainder; + + size_t i = 0, j = 0; + for(i = 0, j = 0; i < limit; i += 8, j += 5) { + if(!base32_8to5(&in[i], 8, &out[j], alphabet)) { + return false; + } + } + + if(remainder && !base32_8to5(&in[i], remainder, &out[j], alphabet)) { + return false; + } + + return true; +} + +size_t base32_encoded_length(size_t inlen) { + uint8_t remainder = inlen % 5; + + return (inlen / 5) * 8 + (remainder * 8 + 4) / 5; +} + +size_t base32_decoded_length(size_t inlen) { + uint8_t remainder = inlen % 8; + + return (inlen / 8) * 5 + (remainder * 5) / 8; +} + +void base32_5to8(const uint8_t* in, uint8_t length, uint8_t* out) { + if(length >= 1) { + out[0] = (in[0] >> 3); + out[1] = (in[0] & 7) << 2; + } + + if(length >= 2) { + out[1] |= (in[1] >> 6); + out[2] = (in[1] >> 1) & 31; + out[3] = (in[1] & 1) << 4; + } + + if(length >= 3) { + out[3] |= (in[2] >> 4); + out[4] = (in[2] & 15) << 1; + } + + if(length >= 4) { + out[4] |= (in[3] >> 7); + out[5] = (in[3] >> 2) & 31; + out[6] = (in[3] & 3) << 3; + } + + if(length >= 5) { + out[6] |= (in[4] >> 5); + out[7] = (in[4] & 31); + } +} + +bool base32_8to5(const uint8_t* in, uint8_t length, uint8_t* out, const char* alphabet) { + if(length == 1 || length == 3 || length == 6 || length > 8) { + return false; + } + + if(alphabet) { + uint8_t decoded[length]; + memset(decoded, 0, sizeof(decoded)); + + for(size_t i = 0; i < length; i++) { + int ret = base32_decode_character(in[i], alphabet); + + if(ret == -1) { + return false; + } else { + decoded[i] = ret; + } + } + + base32_8to5_raw(decoded, length, out); + } else { + base32_8to5_raw(in, length, out); + } + + return true; +} + +void base32_8to5_raw(const uint8_t* in, uint8_t length, uint8_t* out) { + if(length >= 2) { + out[0] = (in[0] << 3); + out[0] |= (in[1] >> 2); + } + + if(length >= 4) { + out[1] = (in[1] & 3) << 6; + out[1] |= (in[2] << 1); + out[1] |= (in[3] >> 4); + } + + if(length >= 5) { + out[2] = (in[3] & 15) << 4; + out[2] |= (in[4] >> 1); + } + + if(length >= 7) { + out[3] = (in[4] & 1) << 7; + out[3] |= (in[5] << 2); + out[3] |= (in[6] >> 3); + } + + if(length >= 8) { + out[4] = (in[6] & 7) << 5; + out[4] |= (in[7] & 31); + } +} + +int base32_encode_character(uint8_t decoded, const char* alphabet) { + if(decoded >> 5) { + return -1; + } + + if(alphabet == BASE32_ALPHABET_RFC4648) { + if(decoded < 26) { + return 'A' + decoded; + } else { + return '2' - 26 + decoded; + } + } + + return alphabet[decoded]; +} + +int base32_decode_character(char encoded, const char* alphabet) { + if(alphabet == BASE32_ALPHABET_RFC4648) { + if(encoded >= 'A' && encoded <= 'Z') { + return encoded - 'A'; + } else if(encoded >= 'a' && encoded <= 'z') { + return encoded - 'a'; + } else if(encoded >= '2' && encoded <= '7') { + return encoded - '2' + 26; + } else { + return -1; + } + } + + const char* occurrence = strchr(alphabet, encoded); + + if(occurrence) { + return occurrence - alphabet; + } else { + return -1; + } +} diff --git a/applications/external/flipbip/lib/crypto/base32.h b/applications/external/flipbip/lib/crypto/base32.h new file mode 100644 index 000000000..5e214aabb --- /dev/null +++ b/applications/external/flipbip/lib/crypto/base32.h @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2017 Saleem Rashid + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BASE32_H__ +#define __BASE32_H__ + +#include +#include +#include + +extern const char* BASE32_ALPHABET_RFC4648; + +char* base32_encode(const uint8_t* in, size_t inlen, char* out, size_t outlen, const char* alphabet); +void base32_encode_unsafe(const uint8_t* in, size_t inlen, uint8_t* out); + +uint8_t* + base32_decode(const char* in, size_t inlen, uint8_t* out, size_t outlen, const char* alphabet); +bool base32_decode_unsafe(const uint8_t* in, size_t inlen, uint8_t* out, const char* alphabet); + +size_t base32_encoded_length(size_t inlen); +size_t base32_decoded_length(size_t inlen); + +#endif diff --git a/applications/external/flipbip/lib/crypto/base58.c b/applications/external/flipbip/lib/crypto/base58.c new file mode 100644 index 000000000..dbcd3832f --- /dev/null +++ b/applications/external/flipbip/lib/crypto/base58.c @@ -0,0 +1,219 @@ +/** + * Copyright (c) 2012-2014 Luke Dashjr + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "base58.h" +#include +#include +#include "memzero.h" +#include "ripemd160.h" +#include "sha2.h" + +const char b58digits_ordered[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; +const int8_t b58digits_map[] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, -1, -1, -1, -1, -1, -1, -1, 9, + 10, 11, 12, 13, 14, 15, 16, -1, 17, 18, 19, 20, 21, -1, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, -1, -1, -1, -1, -1, -1, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, -1, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, -1, -1, -1, -1, +}; + +typedef uint64_t b58_maxint_t; +typedef uint32_t b58_almostmaxint_t; +#define b58_almostmaxint_bits (sizeof(b58_almostmaxint_t) * 8) +static const b58_almostmaxint_t b58_almostmaxint_mask = + ((((b58_maxint_t)1) << b58_almostmaxint_bits) - 1); + +// Decodes a null-terminated Base58 string `b58` to binary and writes the result +// at the end of the buffer `bin` of size `*binszp`. On success `*binszp` is set +// to the number of valid bytes at the end of the buffer. +bool b58tobin(void* bin, size_t* binszp, const char* b58) { + size_t binsz = *binszp; + + if(binsz == 0) { + return false; + } + + const unsigned char* b58u = (const unsigned char*)b58; + unsigned char* binu = bin; + size_t outisz = (binsz + sizeof(b58_almostmaxint_t) - 1) / sizeof(b58_almostmaxint_t); + b58_almostmaxint_t outi[outisz]; + b58_maxint_t t = 0; + b58_almostmaxint_t c = 0; + size_t i = 0, j = 0; + uint8_t bytesleft = binsz % sizeof(b58_almostmaxint_t); + b58_almostmaxint_t zeromask = bytesleft ? (b58_almostmaxint_mask << (bytesleft * 8)) : 0; + unsigned zerocount = 0; + + size_t b58sz = strlen(b58); + + memzero(outi, sizeof(outi)); + + // Leading zeros, just count + for(i = 0; i < b58sz && b58u[i] == '1'; ++i) ++zerocount; + + for(; i < b58sz; ++i) { + if(b58u[i] & 0x80) + // High-bit set on invalid digit + return false; + if(b58digits_map[b58u[i]] == -1) + // Invalid base58 digit + return false; + c = (unsigned)b58digits_map[b58u[i]]; + for(j = outisz; j--;) { + t = ((b58_maxint_t)outi[j]) * 58 + c; + c = t >> b58_almostmaxint_bits; + outi[j] = t & b58_almostmaxint_mask; + } + if(c) + // Output number too big (carry to the next int32) + return false; + if(outi[0] & zeromask) + // Output number too big (last int32 filled too far) + return false; + } + + j = 0; + if(bytesleft) { + for(i = bytesleft; i > 0; --i) { + *(binu++) = (outi[0] >> (8 * (i - 1))) & 0xff; + } + ++j; + } + + for(; j < outisz; ++j) { + for(i = sizeof(*outi); i > 0; --i) { + *(binu++) = (outi[j] >> (8 * (i - 1))) & 0xff; + } + } + + // locate the most significant byte + binu = bin; + for(i = 0; i < binsz; ++i) { + if(binu[i]) break; + } + + // prepend the correct number of null-bytes + if(zerocount > i) { + /* result too large */ + return false; + } + *binszp = binsz - i + zerocount; + + return true; +} + +int b58check(const void* bin, size_t binsz, HasherType hasher_type, const char* base58str) { + unsigned char buf[32] = {0}; + const uint8_t* binc = bin; + unsigned i = 0; + if(binsz < 4) return -4; + hasher_Raw(hasher_type, bin, binsz - 4, buf); + if(memcmp(&binc[binsz - 4], buf, 4)) return -1; + + // Check number of zeros is correct AFTER verifying checksum (to avoid + // possibility of accessing base58str beyond the end) + for(i = 0; binc[i] == '\0' && base58str[i] == '1'; ++i) { + } // Just finding the end of zeros, nothing to do in loop + if(binc[i] == '\0' || base58str[i] == '1') return -3; + + return binc[0]; +} + +bool b58enc(char* b58, size_t* b58sz, const void* data, size_t binsz) { + const uint8_t* bin = data; + int carry = 0; + size_t i = 0, j = 0, high = 0, zcount = 0; + size_t size = 0; + + while(zcount < binsz && !bin[zcount]) ++zcount; + + size = (binsz - zcount) * 138 / 100 + 1; + uint8_t buf[size]; + memzero(buf, size); + + for(i = zcount, high = size - 1; i < binsz; ++i, high = j) { + for(carry = bin[i], j = size - 1; (j > high) || carry; --j) { + carry += 256 * buf[j]; + buf[j] = carry % 58; + carry /= 58; + if(!j) { + // Otherwise j wraps to maxint which is > high + break; + } + } + } + + for(j = 0; j < size && !buf[j]; ++j) + ; + + if(*b58sz <= zcount + size - j) { + *b58sz = zcount + size - j + 1; + return false; + } + + if(zcount) memset(b58, '1', zcount); + for(i = zcount; j < size; ++i, ++j) b58[i] = b58digits_ordered[buf[j]]; + b58[i] = '\0'; + *b58sz = i + 1; + + return true; +} + +int base58_encode_check( + const uint8_t* data, + int datalen, + HasherType hasher_type, + char* str, + int strsize) { + if(datalen > 128) { + return 0; + } + uint8_t buf[datalen + 32]; + memset(buf, 0, sizeof(buf)); + uint8_t* hash = buf + datalen; + memcpy(buf, data, datalen); + hasher_Raw(hasher_type, data, datalen, hash); + size_t res = strsize; + bool success = b58enc(str, &res, buf, datalen + 4); + memzero(buf, sizeof(buf)); + return success ? res : 0; +} + +int base58_decode_check(const char* str, HasherType hasher_type, uint8_t* data, int datalen) { + if(datalen > 128) { + return 0; + } + uint8_t d[datalen + 4]; + memset(d, 0, sizeof(d)); + size_t res = datalen + 4; + if(b58tobin(d, &res, str) != true) { + return 0; + } + uint8_t* nd = d + datalen + 4 - res; + if(b58check(nd, res, hasher_type, str) < 0) { + return 0; + } + memcpy(data, nd, res - 4); + return res - 4; +} diff --git a/applications/external/flipbip/lib/crypto/base58.h b/applications/external/flipbip/lib/crypto/base58.h new file mode 100644 index 000000000..0f7fa66d3 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/base58.h @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BASE58_H__ +#define __BASE58_H__ + +#include +#include +#include "hasher.h" +#include "options.h" + +extern const char b58digits_ordered[]; +extern const int8_t b58digits_map[]; + +int base58_encode_check( + const uint8_t* data, + int len, + HasherType hasher_type, + char* str, + int strsize); +int base58_decode_check(const char* str, HasherType hasher_type, uint8_t* data, int datalen); + +// Private +bool b58tobin(void* bin, size_t* binszp, const char* b58); +int b58check(const void* bin, size_t binsz, HasherType hasher_type, const char* base58str); +bool b58enc(char* b58, size_t* b58sz, const void* data, size_t binsz); + +#endif diff --git a/applications/external/flipbip/lib/crypto/bignum.c b/applications/external/flipbip/lib/crypto/bignum.c new file mode 100644 index 000000000..f0c7d6e43 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/bignum.c @@ -0,0 +1,1834 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * Copyright (c) 2015 Jochen Hoenicke + * Copyright (c) 2016 Alex Beregszaszi + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "bignum.h" + +#include +#include +#include +#include + +#include "memzero.h" +#include "script.h" + +/* + This library implements 256-bit numbers arithmetic. + + An unsigned 256-bit number is represented by a bignum256 structure, that is an + array of nine 32-bit values called limbs. Limbs are digits of the number in + the base 2**29 representation in the little endian order. This means that + bignum256 x; + represents the value + sum([x[i] * 2**(29*i) for i in range(9)). + + A limb of a bignum256 is *normalized* iff it's less than 2**29. + A bignum256 is *normalized* iff every its limb is normalized. + A number is *fully reduced modulo p* iff it is less than p. + A number is *partly reduced modulo p* iff is is less than 2*p. + The number p is usually a prime number such that 2^256 - 2^224 <= p <= 2^256. + + All functions except bn_fast_mod expect that all their bignum256 inputs are + normalized. (The function bn_fast_mod allows the input number to have the + most significant limb unnormalized). All bignum256 outputs of all functions + are guaranteed to be normalized. + + A number can be partly reduced with bn_fast_mod, a partly reduced number can + be fully reduced with bn_mod. + + A function has *constant control flow with regard to its argument* iff the + order in which instructions of the function are executed doesn't depend on the + value of the argument. + A function has *constant memory access flow with regard to its argument* iff + the memory addresses that are acessed and the order in which they are accessed + don't depend on the value of the argument. + A function *has contant control (memory access) flow* iff it has constant + control (memory access) flow with regard to all its arguments. + + The following function has contant control flow with regard to its arugment + n, however is doesn't have constant memory access flow with regard to it: + void (int n, int *a) } + a[0] = 0; + a[n] = 0; // memory address reveals the value of n + } + + Unless stated otherwise all functions are supposed to have both constant + control flow and constant memory access flow. + */ + +#define BN_MAX_DECIMAL_DIGITS 79 // floor(log(2**(LIMBS * BITS_PER_LIMB), 10)) + 1 + +// out_number = (bignum256) in_number +// Assumes in_number is a raw bigendian 256-bit number +// Guarantees out_number is normalized +void bn_read_be(const uint8_t* in_number, bignum256* out_number) { + uint32_t temp = 0; + + for(int i = 0; i < BN_LIMBS - 1; i++) { + uint32_t limb = read_be(in_number + (BN_LIMBS - 2 - i) * 4); + + temp |= limb << (BN_EXTRA_BITS * i); + out_number->val[i] = temp & BN_LIMB_MASK; + + temp = limb >> (32 - BN_EXTRA_BITS * (i + 1)); + } + + out_number->val[BN_LIMBS - 1] = temp; +} + +// out_number = (256BE) in_number +// Assumes in_number < 2**256 +// Guarantess out_number is a raw bigendian 256-bit number +void bn_write_be(const bignum256* in_number, uint8_t* out_number) { + uint32_t temp = in_number->val[BN_LIMBS - 1]; + for(int i = BN_LIMBS - 2; i >= 0; i--) { + uint32_t limb = in_number->val[i]; + + temp = (temp << (BN_BITS_PER_LIMB - BN_EXTRA_BITS * i)) | (limb >> (BN_EXTRA_BITS * i)); + write_be(out_number + (BN_LIMBS - 2 - i) * 4, temp); + + temp = limb; + } +} + +// out_number = (bignum256) in_number +// Assumes in_number is a raw little endian 256-bit number +// Guarantees out_number is normalized +void bn_read_le(const uint8_t* in_number, bignum256* out_number) { + uint32_t temp = 0; + for(int i = 0; i < BN_LIMBS - 1; i++) { + uint32_t limb = read_le(in_number + i * 4); + + temp |= limb << (BN_EXTRA_BITS * i); + out_number->val[i] = temp & BN_LIMB_MASK; + temp = limb >> (32 - BN_EXTRA_BITS * (i + 1)); + } + + out_number->val[BN_LIMBS - 1] = temp; +} + +// out_number = (256LE) in_number +// Assumes in_number < 2**256 +// Guarantess out_number is a raw little endian 256-bit number +void bn_write_le(const bignum256* in_number, uint8_t* out_number) { + uint32_t temp = in_number->val[BN_LIMBS - 1]; + + for(int i = BN_LIMBS - 2; i >= 0; i--) { + uint32_t limb = in_number->val[i]; + temp = (temp << (BN_BITS_PER_LIMB - BN_EXTRA_BITS * i)) | (limb >> (BN_EXTRA_BITS * i)); + write_le(out_number + i * 4, temp); + temp = limb; + } +} + +// out_number = (bignum256) in_number +// Guarantees out_number is normalized +void bn_read_uint32(uint32_t in_number, bignum256* out_number) { + out_number->val[0] = in_number & BN_LIMB_MASK; + out_number->val[1] = in_number >> BN_BITS_PER_LIMB; + for(uint32_t i = 2; i < BN_LIMBS; i++) out_number->val[i] = 0; +} + +// out_number = (bignum256) in_number +// Guarantees out_number is normalized +void bn_read_uint64(uint64_t in_number, bignum256* out_number) { + out_number->val[0] = in_number & BN_LIMB_MASK; + out_number->val[1] = (in_number >>= BN_BITS_PER_LIMB) & BN_LIMB_MASK; + out_number->val[2] = in_number >> BN_BITS_PER_LIMB; + for(uint32_t i = 3; i < BN_LIMBS; i++) out_number->val[i] = 0; +} + +// Returns the bitsize of x +// Assumes x is normalized +// The function doesn't have neither constant control flow nor constant memory +// access flow +int bn_bitcount(const bignum256* x) { + for(int i = BN_LIMBS - 1; i >= 0; i--) { + uint32_t limb = x->val[i]; + if(limb != 0) { + // __builtin_clz returns the number of leading zero bits starting at the + // most significant bit position + return i * BN_BITS_PER_LIMB + (32 - __builtin_clz(limb)); + } + } + return 0; +} + +// Returns the number of decimal digits of x; if x is 0, returns 1 +// Assumes x is normalized +// The function doesn't have neither constant control flow nor constant memory +// access flow +unsigned int bn_digitcount(const bignum256* x) { + bignum256 val = {0}; + bn_copy(x, &val); + + unsigned int digits = 1; + for(unsigned int i = 0; i < BN_MAX_DECIMAL_DIGITS; i += 3) { + uint32_t limb = 0; + + bn_divmod1000(&val, &limb); + + if(limb >= 100) { + digits = i + 3; + } else if(limb >= 10) { + digits = i + 2; + } else if(limb >= 1) { + digits = i + 1; + } + } + + memzero(&val, sizeof(val)); + + return digits; +} + +// x = 0 +// Guarantees x is normalized +void bn_zero(bignum256* x) { + for(int i = 0; i < BN_LIMBS; i++) { + x->val[i] = 0; + } +} + +// x = 1 +// Guarantees x is normalized +void bn_one(bignum256* x) { + x->val[0] = 1; + for(int i = 1; i < BN_LIMBS; i++) { + x->val[i] = 0; + } +} + +// Returns x == 0 +// Assumes x is normalized +int bn_is_zero(const bignum256* x) { + uint32_t result = 0; + for(int i = 0; i < BN_LIMBS; i++) { + result |= x->val[i]; + } + return !result; +} + +// Returns x == 1 +// Assumes x is normalized +int bn_is_one(const bignum256* x) { + uint32_t result = x->val[0] ^ 1; + for(int i = 1; i < BN_LIMBS; i++) { + result |= x->val[i]; + } + return !result; +} + +// Returns x < y +// Assumes x, y are normalized +int bn_is_less(const bignum256* x, const bignum256* y) { + uint32_t res1 = 0; + uint32_t res2 = 0; + for(int i = BN_LIMBS - 1; i >= 0; i--) { + res1 = (res1 << 1) | (x->val[i] < y->val[i]); + res2 = (res2 << 1) | (x->val[i] > y->val[i]); + } + return res1 > res2; +} + +// Returns x == y +// Assumes x, y are normalized +int bn_is_equal(const bignum256* x, const bignum256* y) { + uint32_t result = 0; + for(int i = 0; i < BN_LIMBS; i++) { + result |= x->val[i] ^ y->val[i]; + } + return !result; +} + +// res = cond if truecase else falsecase +// Assumes cond is either 0 or 1 +// Works properly even if &res == &truecase or &res == &falsecase or +// &truecase == &falsecase or &res == &truecase == &falsecase +void bn_cmov( + bignum256* res, + volatile uint32_t cond, + const bignum256* truecase, + const bignum256* falsecase) { + // Intentional use of bitwise OR operator to ensure constant-time + assert((int)(cond == 1) | (int)(cond == 0)); + + uint32_t tmask = -cond; // tmask = 0xFFFFFFFF if cond else 0x00000000 + uint32_t fmask = ~tmask; // fmask = 0x00000000 if cond else 0xFFFFFFFF + + for(int i = 0; i < BN_LIMBS; i++) { + res->val[i] = (truecase->val[i] & tmask) | (falsecase->val[i] & fmask); + } +} + +// x = -x % prime if cond else x, +// Explicitly x = (3 * prime - x if x > prime else 2 * prime - x) if cond else +// else (x if x > prime else x + prime) +// Assumes x is normalized and partly reduced +// Assumes cond is either 1 or 0 +// Guarantees x is normalized +// Assumes prime is normalized and +// 0 < prime < 2**260 == 2**(BITS_PER_LIMB * LIMBS - 1) +void bn_cnegate(volatile uint32_t cond, bignum256* x, const bignum256* prime) { + // Intentional use of bitwise OR operator to ensure constant time + assert((int)(cond == 1) | (int)(cond == 0)); + + uint32_t tmask = -cond; // tmask = 0xFFFFFFFF if cond else 0x00000000 + uint32_t fmask = ~tmask; // fmask = 0x00000000 if cond else 0xFFFFFFFF + + bn_mod(x, prime); + // x < prime + + uint32_t acc1 = 1; + uint32_t acc2 = 0; + + for(int i = 0; i < BN_LIMBS; i++) { + acc1 += (BN_BASE - 1) + 2 * prime->val[i] - x->val[i]; + // acc1 neither overflows 32 bits nor underflows 0 + // Proof: + // acc1 + (BASE - 1) + 2 * prime[i] - x[i] + // >= (BASE - 1) - x >= (2**BITS_PER_LIMB - 1) - (2**BITS_PER_LIMB - 1) + // == 0 + // acc1 + (BASE - 1) + 2 * prime[i] - x[i] + // <= acc1 + (BASE - 1) + 2 * prime[i] + // <= (2**(32 - BITS_PER_LIMB) - 1) + 2 * (2**BITS_PER_LIMB - 1) + + // (2**BITS_PER_LIMB - 1) + // == 7 + 3 * 2**29 < 2**32 + + acc2 += prime->val[i] + x->val[i]; + // acc2 doesn't overflow 32 bits + // Proof: + // acc2 + prime[i] + x[i] + // <= 2**(32 - BITS_PER_LIMB) - 1 + 2 * (2**BITS_PER_LIMB - 1) + // == 2**(32 - BITS_PER_LIMB) + 2**(BITS_PER_LIMB + 1) - 2 + // == 2**30 + 5 < 2**32 + + // x = acc1 & LIMB_MASK if cond else acc2 & LIMB_MASK + x->val[i] = ((acc1 & tmask) | (acc2 & fmask)) & BN_LIMB_MASK; + + acc1 >>= BN_BITS_PER_LIMB; + // acc1 <= 7 == 2**(32 - BITS_PER_LIMB) - 1 + // acc1 == 2**(BITS_PER_LIMB * (i + 1)) + 2 * prime[:i + 1] - x[:i + 1] + // >> BITS_PER_LIMB * (i + 1) + + acc2 >>= BN_BITS_PER_LIMB; + // acc2 <= 7 == 2**(32 - BITS_PER_LIMB) - 1 + // acc2 == prime[:i + 1] + x[:i + 1] >> BITS_PER_LIMB * (i + 1) + } + + // assert(acc1 == 1); // assert prime <= 2**260 + // assert(acc2 == 0); + + // clang-format off + // acc1 == 1 + // Proof: + // acc1 == 2**(BITS_PER_LIMB * LIMBS) + 2 * prime[:LIMBS] - x[:LIMBS] >> BITS_PER_LIMB * LIMBS + // == 2**(BITS_PER_LIMB * LIMBS) + 2 * prime - x >> BITS_PER_LIMB * LIMBS + // <= 2**(BITS_PER_LIMB * LIMBS) + 2 * prime >> BITS_PER_LIMB * LIMBS + // <= 2**(BITS_PER_LIMB * LIMBS) + 2 * (2**(BITS_PER_LIMB * LIMBS - 1) - 1) >> BITS_PER_LIMB * LIMBS + // <= 2**(BITS_PER_LIMB * LIMBS) + 2**(BITS_PER_LIMB * LIMBS) - 2 >> BITS_PER_LIMB * LIMBS + // == 1 + + // acc1 == 2**(BITS_PER_LIMB * LIMBS) + 2 * prime[:LIMBS] - x[:LIMBS] >> BITS_PER_LIMB * LIMBS + // == 2**(BITS_PER_LIMB * LIMBS) + 2 * prime - x >> BITS_PER_LIMB * LIMBS + // >= 2**(BITS_PER_LIMB * LIMBS) + 0 >> BITS_PER_LIMB * LIMBS + // == 1 + + // acc2 == 0 + // Proof: + // acc2 == prime[:LIMBS] + x[:LIMBS] >> BITS_PER_LIMB * LIMBS + // == prime + x >> BITS_PER_LIMB * LIMBS + // <= 2 * prime - 1 >> BITS_PER_LIMB * LIMBS + // <= 2 * (2**(BITS_PER_LIMB * LIMBS - 1) - 1) - 1 >> 261 + // == 2**(BITS_PER_LIMB * LIMBS) - 3 >> BITS_PER_LIMB * LIMBS + // == 0 + // clang-format on +} + +// x <<= 1 +// Assumes x is normalized, x < 2**260 == 2**(LIMBS*BITS_PER_LIMB - 1) +// Guarantees x is normalized +void bn_lshift(bignum256* x) { + for(int i = BN_LIMBS - 1; i > 0; i--) { + x->val[i] = ((x->val[i] << 1) & BN_LIMB_MASK) | (x->val[i - 1] >> (BN_BITS_PER_LIMB - 1)); + } + x->val[0] = (x->val[0] << 1) & BN_LIMB_MASK; +} + +// x >>= 1, i.e. x = floor(x/2) +// Assumes x is normalized +// Guarantees x is normalized +// If x is partly reduced (fully reduced) modulo prime, +// guarantess x will be partly reduced (fully reduced) modulo prime +void bn_rshift(bignum256* x) { + for(int i = 0; i < BN_LIMBS - 1; i++) { + x->val[i] = (x->val[i] >> 1) | ((x->val[i + 1] & 1) << (BN_BITS_PER_LIMB - 1)); + } + x->val[BN_LIMBS - 1] >>= 1; +} + +// Sets i-th least significant bit (counting from zero) +// Assumes x is normalized and 0 <= i < 261 == LIMBS*BITS_PER_LIMB +// Guarantees x is normalized +// The function has constant control flow but not constant memory access flow +// with regard to i +void bn_setbit(bignum256* x, uint16_t i) { + assert(i < BN_LIMBS * BN_BITS_PER_LIMB); + x->val[i / BN_BITS_PER_LIMB] |= (1u << (i % BN_BITS_PER_LIMB)); +} + +// clears i-th least significant bit (counting from zero) +// Assumes x is normalized and 0 <= i < 261 == LIMBS*BITS_PER_LIMB +// Guarantees x is normalized +// The function has constant control flow but not constant memory access flow +// with regard to i +void bn_clearbit(bignum256* x, uint16_t i) { + assert(i < BN_LIMBS * BN_BITS_PER_LIMB); + x->val[i / BN_BITS_PER_LIMB] &= ~(1u << (i % BN_BITS_PER_LIMB)); +} + +// returns i-th least significant bit (counting from zero) +// Assumes x is normalized and 0 <= i < 261 == LIMBS*BITS_PER_LIMB +// The function has constant control flow but not constant memory access flow +// with regard to i +uint32_t bn_testbit(const bignum256* x, uint16_t i) { + assert(i < BN_LIMBS * BN_BITS_PER_LIMB); + return (x->val[i / BN_BITS_PER_LIMB] >> (i % BN_BITS_PER_LIMB)) & 1; +} + +// res = x ^ y +// Assumes x, y are normalized +// Guarantees res is normalized +// Works properly even if &res == &x or &res == &y or &res == &x == &y +void bn_xor(bignum256* res, const bignum256* x, const bignum256* y) { + for(int i = 0; i < BN_LIMBS; i++) { + res->val[i] = x->val[i] ^ y->val[i]; + } +} + +// x = x / 2 % prime +// Explicitly x = x / 2 if is_even(x) else (x + prime) / 2 +// Assumes x is normalized, x + prime < 261 == LIMBS * BITS_PER_LIMB +// Guarantees x is normalized +// If x is partly reduced (fully reduced) modulo prime, +// guarantess x will be partly reduced (fully reduced) modulo prime +// Assumes prime is an odd number and normalized +void bn_mult_half(bignum256* x, const bignum256* prime) { + // x = x / 2 if is_even(x) else (x + prime) / 2 + + uint32_t x_is_odd_mask = -(x->val[0] & 1); // x_is_odd_mask = 0xFFFFFFFF if is_odd(x) else 0 + + uint32_t acc = (x->val[0] + (prime->val[0] & x_is_odd_mask)) >> 1; + // acc < 2**BITS_PER_LIMB + // Proof: + // acc == x[0] + prime[0] & x_is_odd_mask >> 1 + // <= (2**(BITS_PER_LIMB) - 1) + (2**(BITS_PER_LIMB) - 1) >> 1 + // == 2**(BITS_PER_LIMB + 1) - 2 >> 1 + // < 2**(BITS_PER_LIMB) + + for(int i = 0; i < BN_LIMBS - 1; i++) { + uint32_t temp = (x->val[i + 1] + (prime->val[i + 1] & x_is_odd_mask)); + // temp < 2**(BITS_PER_LIMB + 1) + // Proof: + // temp == x[i + 1] + val[i + 1] & x_is_odd_mask + // <= (2**(BITS_PER_LIMB) - 1) + (2**(BITS_PER_LIMB) - 1) + // < 2**(BITS_PER_LIMB + 1) + + acc += (temp & 1) << (BN_BITS_PER_LIMB - 1); + // acc doesn't overflow 32 bits + // Proof: + // acc + (temp & 1 << BITS_PER_LIMB - 1) + // <= 2**(BITS_PER_LIMB + 1) + 2**(BITS_PER_LIMB - 1) + // <= 2**30 + 2**28 < 2**32 + + x->val[i] = acc & BN_LIMB_MASK; + acc >>= BN_BITS_PER_LIMB; + acc += temp >> 1; + // acc < 2**(BITS_PER_LIMB + 1) + // Proof: + // acc + (temp >> 1) + // <= (2**(32 - BITS_PER_LIMB) - 1) + (2**(BITS_PER_LIMB + 1) - 1 >> 1) + // == 7 + 2**(BITS_PER_LIMB) - 1 < 2**(BITS_PER_LIMB + 1) + + // acc == x[:i+2]+(prime[:i+2] & x_is_odd_mask) >> BITS_PER_LIMB * (i+1) + } + x->val[BN_LIMBS - 1] = acc; + + // assert(acc >> BITS_PER_LIMB == 0); + // acc >> BITS_PER_LIMB == 0 + // Proof: + // acc + // == x[:LIMBS] + (prime[:LIMBS] & x_is_odd_mask) >> BITS_PER_LIMB*LIMBS + // == x + (prime & x_is_odd_mask) >> BITS_PER_LIMB * LIMBS + // <= x + prime >> BITS_PER_LIMB * LIMBS + // <= 2**(BITS_PER_LIMB * LIMBS) - 1 >> BITS_PER_LIMB * LIMBS + // == 0 +} + +// x = x * k % prime +// Assumes x is normalized, 0 <= k <= 8 = 2**(32 - BITS_PER_LIMB) +// Assumes prime is normalized and 2^256 - 2^224 <= prime <= 2^256 +// Guarantees x is normalized and partly reduced modulo prime +void bn_mult_k(bignum256* x, uint8_t k, const bignum256* prime) { + assert(k <= 8); + + for(int i = 0; i < BN_LIMBS; i++) { + x->val[i] = k * x->val[i]; + // x[i] doesn't overflow 32 bits + // k * x[i] <= 2**(32 - BITS_PER_LIMB) * (2**BITS_PER_LIMB - 1) + // < 2**(32 - BITS_PER_LIMB) * 2**BITS_PER_LIMB == 2**32 + } + + bn_fast_mod(x, prime); +} + +// Reduces partly reduced x modulo prime +// Explicitly x = x if x < prime else x - prime +// Assumes x is partly reduced modulo prime +// Guarantees x is fully reduced modulo prime +// Assumes prime is nonzero and normalized +void bn_mod(bignum256* x, const bignum256* prime) { + uint32_t x_less_prime = bn_is_less(x, prime); + + bignum256 temp = {0}; + bn_subtract(x, prime, &temp); + bn_cmov(x, x_less_prime, x, &temp); + + memzero(&temp, sizeof(temp)); +} + +// Auxiliary function for bn_multiply +// res = k * x +// Assumes k and x are normalized +// Guarantees res is normalized 18 digit little endian number in base 2**29 +void bn_multiply_long(const bignum256* k, const bignum256* x, uint32_t res[2 * BN_LIMBS]) { + // Uses long multiplication in base 2**29, see + // https://en.wikipedia.org/wiki/Multiplication_algorithm#Long_multiplication + + uint64_t acc = 0; + + // compute lower half + for(int i = 0; i < BN_LIMBS; i++) { + for(int j = 0; j <= i; j++) { + acc += k->val[j] * (uint64_t)x->val[i - j]; + // acc doesn't overflow 64 bits + // Proof: + // acc <= acc + sum([k[j] * x[i-j] for j in range(i)]) + // <= (2**(64 - BITS_PER_LIMB) - 1) + + // LIMBS * (2**BITS_PER_LIMB - 1) * (2**BITS_PER_LIMB - 1) + // == (2**35 - 1) + 9 * (2**29 - 1) * (2**29 - 1) + // <= 2**35 + 9 * 2**58 < 2**64 + } + + res[i] = acc & BN_LIMB_MASK; + acc >>= BN_BITS_PER_LIMB; + // acc <= 2**35 - 1 == 2**(64 - BITS_PER_LIMB) - 1 + } + + // compute upper half + for(int i = BN_LIMBS; i < 2 * BN_LIMBS - 1; i++) { + for(int j = i - BN_LIMBS + 1; j < BN_LIMBS; j++) { + acc += k->val[j] * (uint64_t)x->val[i - j]; + // acc doesn't overflow 64 bits + // Proof: + // acc <= acc + sum([k[j] * x[i-j] for j in range(i)]) + // <= (2**(64 - BITS_PER_LIMB) - 1) + // LIMBS * (2**BITS_PER_LIMB - 1) * (2**BITS_PER_LIMB - 1) + // == (2**35 - 1) + 9 * (2**29 - 1) * (2**29 - 1) + // <= 2**35 + 9 * 2**58 < 2**64 + } + + res[i] = acc & (BN_BASE - 1); + acc >>= BN_BITS_PER_LIMB; + // acc < 2**35 == 2**(64 - BITS_PER_LIMB) + } + + res[2 * BN_LIMBS - 1] = acc; +} + +// Auxiliary function for bn_multiply +// Assumes 0 <= d <= 8 == LIMBS - 1 +// Assumes res is normalized and res < 2**(256 + 29*d + 31) +// Guarantess res in normalized and res < 2 * prime * 2**(29*d) +// Assumes prime is normalized, 2**256 - 2**224 <= prime <= 2**256 +void bn_multiply_reduce_step(uint32_t res[2 * BN_LIMBS], const bignum256* prime, uint32_t d) { + // clang-format off + // Computes res = res - (res // 2**(256 + BITS_PER_LIMB * d)) * prime * 2**(BITS_PER_LIMB * d) + + // res - (res // 2**(256 + BITS_PER_LIMB * d)) * prime * 2**(BITS_PER_LIMB * d) < 2 * prime * 2**(BITS_PER_LIMB * d) + // Proof: + // res - res // (2**(256 + BITS_PER_LIMB * d)) * 2**(BITS_PER_LIMB * d) * prime + // == res - res // (2**(256 + BITS_PER_LIMB * d)) * 2**(BITS_PER_LIMB * d) * (2**256 - (2**256 - prime)) + // == res - res // (2**(256 + BITS_PER_LIMB * d)) * 2**(BITS_PER_LIMB * d) * 2**256 + res // (2**(256 + BITS_PER_LIMB * d)) * 2**(BITS_PER_LIMB * d) * (2**256 - prime) + // == (res % 2**(256 + BITS_PER_LIMB * d)) + res // (2**256 + BITS_PER_LIMB * d) * 2**(BITS_PER_LIMB * d) * (2**256 - prime) + // <= (2**(256 + 29*d + 31) % 2**(256 + 29*d)) + (2**(256 + 29*d + 31) - 1) / (2**256 + 29*d) * 2**(29*d) * (2**256 - prime) + // <= 2**(256 + 29*d) + 2**(256 + 29*d + 31) / (2**256 + 29*d) * 2**(29*d) * (2**256 - prime) + // == 2**(256 + 29*d) + 2**31 * 2**(29*d) * (2**256 - prime) + // == 2**(29*d) * (2**256 + 2**31 * (2*256 - prime)) + // <= 2**(29*d) * (2**256 + 2**31 * 2*224) + // <= 2**(29*d) * (2**256 + 2**255) + // <= 2**(29*d) * 2 * (2**256 - 2**224) + // <= 2 * prime * 2**(29*d) + // clang-format on + + uint32_t coef = (res[d + BN_LIMBS - 1] >> (256 - (BN_LIMBS - 1) * BN_BITS_PER_LIMB)) + + (res[d + BN_LIMBS] << ((BN_LIMBS * BN_BITS_PER_LIMB) - 256)); + + // coef == res // 2**(256 + BITS_PER_LIMB * d) + + // coef < 2**31 + // Proof: + // coef == res // 2**(256 + BITS_PER_LIMB * d) + // < 2**(256 + 29 * d + 31) // 2**(256 + 29 * d) + // == 2**31 + + const int shift = 31; + uint64_t acc = 1ull << shift; + + for(int i = 0; i < BN_LIMBS; i++) { + acc += (((uint64_t)(BN_BASE - 1)) << shift) + res[d + i] - prime->val[i] * (uint64_t)coef; + // acc neither overflow 64 bits nor underflow zero + // Proof: + // acc + ((BASE - 1) << shift) + res[d + i] - prime[i] * coef + // >= ((BASE - 1) << shift) - prime[i] * coef + // == 2**shift * (2**BITS_PER_LIMB - 1) - (2**BITS_PER_LIMB - 1) * + // (2**31 - 1) + // == (2**shift - 2**31 + 1) * (2**BITS_PER_LIMB - 1) + // == (2**31 - 2**31 + 1) * (2**29 - 1) + // == 2**29 - 1 > 0 + // acc + ((BASE - 1) << shift) + res[d + i] - prime[i] * coef + // <= acc + ((BASE - 1) << shift) + res[d+i] + // <= (2**(64 - BITS_PER_LIMB) - 1) + 2**shift * (2**BITS_PER_LIMB - 1) + // + (2*BITS_PER_LIMB - 1) + // == (2**(64 - BITS_PER_LIMB) - 1) + (2**shift + 1) * + // (2**BITS_PER_LIMB - 1) + // == (2**35 - 1) + (2**31 + 1) * (2**29 - 1) + // <= 2**35 + 2**60 + 2**29 < 2**64 + + res[d + i] = acc & BN_LIMB_MASK; + acc >>= BN_BITS_PER_LIMB; + // acc <= 2**(64 - BITS_PER_LIMB) - 1 == 2**35 - 1 + + // acc == (1 << BITS_PER_LIMB * (i + 1) + shift) + res[d : d + i + 1] + // - coef * prime[:i + 1] >> BITS_PER_LIMB * (i + 1) + } + + // acc += (((uint64_t)(BASE - 1)) << shift) + res[d + LIMBS]; + // acc >>= BITS_PER_LIMB; + // assert(acc <= 1ul << shift); + + // clang-format off + // acc == 1 << shift + // Proof: + // acc + // == (1 << BITS_PER_LIMB * (LIMBS + 1) + shift) + res[d : d + LIMBS + 1] - coef * prime[:LIMBS] >> BITS_PER_LIMB * (LIMBS + 1) + // == (1 << BITS_PER_LIMB * (LIMBS + 1) + shift) + res[d : d + LIMBS + 1] - coef * prime >> BITS_PER_LIMB * (LIMBS + 1) + + // == (1 << BITS_PER_LIMB * (LIMBS + 1) + shift) + (res[d : d + LIMBS + 1] - coef * prime) >> BITS_PER_LIMB * (LIMBS + 1) + // <= (1 << BITS_PER_LIMB * (LIMBS + 1) + shift) + (res[:d] + BASE**d * res[d : d + LIMBS + 1] - BASE**d * coef * prime)//BASE**d >> BITS_PER_LIMB * (LIMBS + 1) + // <= (1 << BITS_PER_LIMB * (LIMBS + 1) + shift) + (res - BASE**d * coef * prime) // BASE**d >> BITS_PER_LIMB * (LIMBS + 1) + // == (1 << BITS_PER_LIMB * (LIMBS + 1) + shift) + (2 * prime * BASE**d) // BASE**d >> BITS_PER_LIMB * (LIMBS + 1) + // <= (1 << 321) + 2 * 2**256 >> 290 + // == 1 << 31 == 1 << shift + + // == (1 << BITS_PER_LIMB * (LIMBS + 1) + shift) + res[d : d + LIMBS + 1] - coef * prime[:LIMBS + 1] >> BITS_PER_LIMB * (LIMBS + 1) + // >= (1 << BITS_PER_LIMB * (LIMBS + 1) + shift) + 0 >> BITS_PER_LIMB * (LIMBS + 1) + // == 1 << shift + // clang-format on + + res[d + BN_LIMBS] = 0; +} + +// Auxiliary function for bn_multiply +// Partly reduces res and stores both in x and res +// Assumes res in normalized and res < 2**519 +// Guarantees x is normalized and partly reduced modulo prime +// Assumes prime is normalized, 2**256 - 2**224 <= prime <= 2**256 +void bn_multiply_reduce(bignum256* x, uint32_t res[2 * BN_LIMBS], const bignum256* prime) { + for(int i = BN_LIMBS - 1; i >= 0; i--) { + // res < 2**(256 + 29*i + 31) + // Proof: + // if i == LIMBS - 1: + // res < 2**519 + // == 2**(256 + 29 * 8 + 31) + // == 2**(256 + 29 * (LIMBS - 1) + 31) + // else: + // res < 2 * prime * 2**(29 * (i + 1)) + // <= 2**256 * 2**(29*i + 29) < 2**(256 + 29*i + 31) + bn_multiply_reduce_step(res, prime, i); + } + + for(int i = 0; i < BN_LIMBS; i++) { + x->val[i] = res[i]; + } +} + +// x = k * x % prime +// Assumes k, x are normalized, k * x < 2**519 +// Guarantees x is normalized and partly reduced modulo prime +// Assumes prime is normalized, 2**256 - 2**224 <= prime <= 2**256 +void bn_multiply(const bignum256* k, bignum256* x, const bignum256* prime) { + uint32_t res[2 * BN_LIMBS] = {0}; + + bn_multiply_long(k, x, res); + bn_multiply_reduce(x, res, prime); + + memzero(res, sizeof(res)); +} + +// Partly reduces x modulo prime +// Assumes limbs of x except the last (the most significant) one are normalized +// Assumes prime is normalized and 2^256 - 2^224 <= prime <= 2^256 +// Guarantees x is normalized and partly reduced modulo prime +void bn_fast_mod(bignum256* x, const bignum256* prime) { + // Computes x = x - (x // 2**256) * prime + + // x < 2**((LIMBS - 1) * BITS_PER_LIMB + 32) == 2**264 + + // x - (x // 2**256) * prime < 2 * prime + // Proof: + // x - (x // 2**256) * prime + // == x - (x // 2**256) * (2**256 - (2**256 - prime)) + // == x - ((x // 2**256) * 2**256) + (x // 2**256) * (2**256 - prime) + // == (x % prime) + (x // 2**256) * (2**256 - prime) + // <= prime - 1 + (2**264 // 2**256) * (2**256 - prime) + // <= 2**256 + 2**8 * 2**224 == 2**256 + 2**232 + // < 2 * (2**256 - 2**224) + // <= 2 * prime + + // x - (x // 2**256 - 1) * prime < 2 * prime + // Proof: + // x - (x // 2**256) * prime + prime + // == x - (x // 2**256) * (2**256 - (2**256 - prime)) + prime + // == x - ((x//2**256) * 2**256) + (x//2**256) * (2**256 - prime) + prime + // == (x % prime) + (x // 2**256) * (2**256 - prime) + prime + // <= 2 * prime - 1 + (2**264 // 2**256) * (2**256 - prime) + // <= 2 * prime + 2**8 * 2**224 == 2**256 + 2**232 + 2**256 - 2**224 + // < 2 * (2**256 - 2**224) + // <= 2 * prime + + uint32_t coef = x->val[BN_LIMBS - 1] >> (256 - ((BN_LIMBS - 1) * BN_BITS_PER_LIMB)); + + // clang-format off + // coef == x // 2**256 + // 0 <= coef < 2**((LIMBS - 1) * BITS_PER_LIMB + 32 - 256) == 256 + // Proof: + //* Let x[[a : b] be the number consisting of a-th to (b-1)-th bit of the number x. + // x[LIMBS - 1] >> (256 - ((LIMBS - 1) * BITS_PER_LIMB)) + // == x[[(LIMBS - 1) * BITS_PER_LIMB : (LIMBS - 1) * BITS_PER_LIMB + 32]] >> (256 - ((LIMBS - 1) * BITS_PER_LIMB)) + // == x[[256 - ((LIMBS - 1) * BITS_PER_LIMB) + (LIMBS - 1) * BITS_PER_LIMB : (LIMBS - 1) * BITS_PER_LIMB + 32]] + // == x[[256 : (LIMBS - 1) * BITS_PER_LIMB + 32]] + // == x[[256 : 264]] == x // 2**256 + // clang-format on + + const int shift = 8; + uint64_t acc = 1ull << shift; + + for(int i = 0; i < BN_LIMBS; i++) { + acc += (((uint64_t)(BN_BASE - 1)) << shift) + x->val[i] - prime->val[i] * (uint64_t)coef; + // acc neither overflows 64 bits nor underflows 0 + // Proof: + // acc + (BASE - 1 << shift) + x[i] - prime[i] * coef + // >= (BASE - 1 << shift) - prime[i] * coef + // >= 2**shift * (2**BITS_PER_LIMB - 1) - (2**BITS_PER_LIMB - 1) * 255 + // == (2**shift - 255) * (2**BITS_PER_LIMB - 1) + // == (2**8 - 255) * (2**29 - 1) == 2**29 - 1 >= 0 + // acc + (BASE - 1 << shift) + x[i] - prime[i] * coef + // <= acc + ((BASE - 1) << shift) + x[i] + // <= (2**(64 - BITS_PER_LIMB) - 1) + 2**shift * (2**BITS_PER_LIMB - 1) + // + (2**32 - 1) + // == (2**35 - 1) + 2**8 * (2**29 - 1) + 2**32 + // < 2**35 + 2**37 + 2**32 < 2**64 + + x->val[i] = acc & BN_LIMB_MASK; + acc >>= BN_BITS_PER_LIMB; + // acc <= 2**(64 - BITS_PER_LIMB) - 1 == 2**35 - 1 + + // acc == (1 << BITS_PER_LIMB * (i + 1) + shift) + x[:i + 1] + // - coef * prime[:i + 1] >> BITS_PER_LIMB * (i + 1) + } + + // assert(acc == 1 << shift); + + // clang-format off + // acc == 1 << shift + // Proof: + // acc + // == (1 << BITS_PER_LIMB * LIMBS + shift) + x[:LIMBS] - coef * prime[:LIMBS] >> BITS_PER_LIMB * LIMBS + // == (1 << BITS_PER_LIMB * LIMBS + shift) + (x - coef * prime) >> BITS_PER_LIMB * LIMBS + // <= (1 << BITS_PER_LIMB * LIMBS + shift) + (2 * prime) >> BITS_PER_LIMB * LIMBS + // <= (1 << BITS_PER_LIMB * LIMBS + shift) + 2 * 2**256 >> BITS_PER_LIMB * LIMBS + // <= 2**269 + 2**257 >> 2**261 + // <= 1 << 8 == 1 << shift + + // acc + // == (1 << BITS_PER_LIMB * LIMBS + shift) + x[:LIMBS] - coef * prime[:LIMBS] >> BITS_PER_LIMB * LIMBS + // >= (1 << BITS_PER_LIMB * LIMBS + shift) + 0 >> BITS_PER_LIMB * LIMBS + // == (1 << BITS_PER_LIMB * LIMBS + shift) + 0 >> BITS_PER_LIMB * LIMBS + // <= 1 << 8 == 1 << shift + // clang-format on +} + +// res = x**e % prime +// Assumes both x and e are normalized, x < 2**259 +// Guarantees res is normalized and partly reduced modulo prime +// Works properly even if &x == &res +// Assumes prime is normalized, 2**256 - 2**224 <= prime <= 2**256 +// The function doesn't have neither constant control flow nor constant memory +// access flow with regard to e +void bn_power_mod(const bignum256* x, const bignum256* e, const bignum256* prime, bignum256* res) { + // Uses iterative right-to-left exponentiation by squaring, see + // https://en.wikipedia.org/wiki/Modular_exponentiation#Right-to-left_binary_method + + bignum256 acc = {0}; + bn_copy(x, &acc); + + bn_one(res); + for(int i = 0; i < BN_LIMBS; i++) { + uint32_t limb = e->val[i]; + + for(int j = 0; j < BN_BITS_PER_LIMB; j++) { + // Break if the following bits of the last limb are zero + if(i == BN_LIMBS - 1 && limb == 0) break; + + if(limb & 1) + // acc * res < 2**519 + // Proof: + // acc * res <= max(2**259 - 1, 2 * prime) * (2 * prime) + // == max(2**259 - 1, 2**257) * 2**257 < 2**259 * 2**257 + // == 2**516 < 2**519 + bn_multiply(&acc, res, prime); + + limb >>= 1; + // acc * acc < 2**519 + // Proof: + // acc * acc <= max(2**259 - 1, 2 * prime)**2 + // <= (2**259)**2 == 2**518 < 2**519 + bn_multiply(&acc, &acc, prime); + } + // acc == x**(e[:i + 1]) % prime + } + + memzero(&acc, sizeof(acc)); +} + +// x = sqrt(x) % prime +// Explicitly x = x**((prime+1)/4) % prime +// The other root is -sqrt(x) +// Assumes x is normalized, x < 2**259 and quadratic residuum mod prime +// Assumes prime is a prime number, prime % 4 == 3, it is normalized and +// 2**256 - 2**224 <= prime <= 2**256 +// Guarantees x is normalized and fully reduced modulo prime +// The function doesn't have neither constant control flow nor constant memory +// access flow with regard to prime +void bn_sqrt(bignum256* x, const bignum256* prime) { + // Uses the Lagrange formula for the primes of the special form, see + // http://en.wikipedia.org/wiki/Quadratic_residue#Prime_or_prime_power_modulus + // If prime % 4 == 3, then sqrt(x) % prime == x**((prime+1)//4) % prime + + assert(prime->val[BN_LIMBS - 1] % 4 == 3); + + // e = (prime + 1) // 4 + bignum256 e = {0}; + bn_copy(prime, &e); + bn_addi(&e, 1); + bn_rshift(&e); + bn_rshift(&e); + + bn_power_mod(x, &e, prime, x); + bn_mod(x, prime); + + memzero(&e, sizeof(e)); +} + +// a = 1/a % 2**n +// Assumes a is odd, 1 <= n <= 32 +// The function doesn't have neither constant control flow nor constant memory +// access flow with regard to n +uint32_t inverse_mod_power_two(uint32_t a, uint32_t n) { + // Uses "Explicit Quadratic Modular inverse modulo 2" from section 3.3 of "On + // Newton-Raphson iteration for multiplicative inverses modulo prime powers" + // by Jean-Guillaume Dumas, see + // https://arxiv.org/pdf/1209.6626.pdf + + // 1/a % 2**n + // = (2-a) * product([1 + (a-1)**(2**i) for i in range(1, floor(log2(n)))]) + + uint32_t acc = 2 - a; + uint32_t f = a - 1; + + // mask = (1 << n) - 1 + uint32_t mask = n == 32 ? 0xFFFFFFFF : (1u << n) - 1; + + for(uint32_t i = 1; i < n; i <<= 1) { + f = (f * f) & mask; + acc = (acc * (1 + f)) & mask; + } + + return acc; +} + +// x = (x / 2**BITS_PER_LIMB) % prime +// Assumes both x and prime are normalized +// Assumes prime is an odd number and normalized +// Guarantees x is normalized +// If x is partly reduced (fully reduced) modulo prime, +// guarantess x will be partly reduced (fully reduced) modulo prime +void bn_divide_base(bignum256* x, const bignum256* prime) { + // Uses an explicit formula for the modular inverse of power of two + // (x / 2**n) % prime == (x + ((-x / prime) % 2**n) * prime) // 2**n + // Proof: + // (x + ((-x / prime) % 2**n) * prime) % 2**n + // == (x - x / prime * prime) % 2**n + // == 0 + // (x + ((-1 / prime) % 2**n) * prime) % prime + // == x + // if x < prime: + // (x + ((-x / prime) % 2**n) * prime) // 2**n + // <= ((prime - 1) + (2**n - 1) * prime) / 2**n + // == (2**n * prime - 1) / 2**n == prime - 1 / 2**n < prime + // if x < 2 * prime: + // (x + ((-x / prime) % 2**n) * prime) // 2**n + // <= ((2 * prime - 1) + (2**n - 1) * prime) / 2**n + // == (2**n * prime + prime - 1) / 2**n + // == prime + (prime - 1) / 2**n < 2 * prime + + // m = (-x / prime) % 2**BITS_PER_LIMB + uint32_t m = (x->val[0] * (BN_BASE - inverse_mod_power_two(prime->val[0], BN_BITS_PER_LIMB))) & + BN_LIMB_MASK; + // m < 2**BITS_PER_LIMB + + uint64_t acc = x->val[0] + (uint64_t)m * prime->val[0]; + acc >>= BN_BITS_PER_LIMB; + + for(int i = 1; i < BN_LIMBS; i++) { + acc = acc + x->val[i] + (uint64_t)m * prime->val[i]; + // acc does not overflow 64 bits + // acc == acc + x + m * prime + // <= 2**(64 - BITS_PER_LIMB) + 2**(BITS_PER_LIMB) + // 2**(BITS_PER_LIMB) * 2**(BITS_PER_LIMB) + // <= 2**(2 * BITS_PER_LIMB) + 2**(64 - BITS_PER_LIMB) + + // 2**(BITS_PER_LIMB) + // <= 2**58 + 2**35 + 2**29 < 2**64 + + x->val[i - 1] = acc & BN_LIMB_MASK; + acc >>= BN_BITS_PER_LIMB; + // acc < 2**35 == 2**(64 - BITS_PER_LIMB) + + // acc == x[:i + 1] + m * prime[:i + 1] >> BITS_PER_LIMB * (i + 1) + } + + x->val[BN_LIMBS - 1] = acc; + + assert(acc >> BN_BITS_PER_LIMB == 0); + + // clang-format off + // acc >> BITS_PER_LIMB == 0 + // Proof: + // acc >> BITS_PER_LIMB + // == (x[:LIMB] + m * prime[:LIMB] >> BITS_PER_LIMB * LIMBS) >> BITS_PER_LIMB * (LIMBS + 1) + // == x + m * prime >> BITS_PER_LIMB * (LIMBS + 1) + // <= (2**(BITS_PER_LIMB * LIMBS) - 1) + (2**BITS_PER_LIMB - 1) * (2**(BITS_PER_LIMB * LIMBS) - 1) >> BITS_PER_LIMB * (LIMBS + 1) + // == 2**(BITS_PER_LIMB * LIMBS) - 1 + 2**(BITS_PER_LIMB * (LIMBS + 1)) - 2**(BITS_PER_LIMB * LIMBS) - 2**BITS_PER_LIMB + 1 >> BITS_PER_LIMB * (LIMBS + 1) + // == 2**(BITS_PER_LIMB * (LIMBS + 1)) - 2**BITS_PER_LIMB >> BITS_PER_LIMB * (LIMBS + 1) + // == 0 + // clang-format on +} + +#if !USE_INVERSE_FAST +// x = 1/x % prime if x != 0 else 0 +// Assumes x is normalized +// Assumes prime is a prime number +// Guarantees x is normalized and fully reduced modulo prime +// Assumes prime is normalized, 2**256 - 2**224 <= prime <= 2**256 +// The function doesn't have neither constant control flow nor constant memory +// access flow with regard to prime +static void bn_inverse_slow(bignum256* x, const bignum256* prime) { + // Uses formula 1/x % prime == x**(prime - 2) % prime + // See https://en.wikipedia.org/wiki/Fermat%27s_little_theorem + + bn_fast_mod(x, prime); + + // e = prime - 2 + bignum256 e = {0}; + bn_read_uint32(2, &e); + bn_subtract(prime, &e, &e); + + bn_power_mod(x, &e, prime, x); + bn_mod(x, prime); + + memzero(&e, sizeof(e)); +} +#endif + +#if false +// x = 1/x % prime if x != 0 else 0 +// Assumes x is is_normalized +// Assumes GCD(x, prime) = 1 +// Guarantees x is normalized and fully reduced modulo prime +// Assumes prime is odd, normalized, 2**256 - 2**224 <= prime <= 2**256 +// The function doesn't have neither constant control flow nor constant memory +// access flow with regard to prime and x +static void bn_inverse_fast(bignum256 *x, const bignum256 *prime) { + // "The Almost Montgomery Inverse" from the section 3 of "Constant Time + // Modular Inversion" by Joppe W. Bos + // See http://www.joppebos.com/files/CTInversion.pdf + + /* + u = prime + v = x & prime + s = 1 + r = 0 + + k = 0 + while v != 1: + k += 1 + if is_even(u): + u = u // 2 + s = 2 * s + elif is_even(v): + v = v // 2 + r = 2 * r + elif v < u: + u = (u - v) // 2 + r = r + s + s = 2 * s + else: + v = (v - u) // 2 + s = r + s + r = 2 * r + + s = (s / 2**k) % prime + return s + */ + + if (bn_is_zero(x)) return; + + bn_fast_mod(x, prime); + bn_mod(x, prime); + + bignum256 u = {0}, v = {0}, r = {0}, s = {0}; + bn_copy(prime, &u); + bn_copy(x, &v); + bn_one(&s); + bn_zero(&r); + + int k = 0; + while (!bn_is_one(&v)) { + if ((u.val[0] & 1) == 0) { + bn_rshift(&u); + bn_lshift(&s); + } else if ((v.val[0] & 1) == 0) { + bn_rshift(&v); + bn_lshift(&r); + } else if (bn_is_less(&v, &u)) { + bn_subtract(&u, &v, &u); + bn_rshift(&u); + bn_add(&r, &s); + bn_lshift(&s); + } else { + bn_subtract(&v, &u, &v); + bn_rshift(&v); + bn_add(&s, &r); + bn_lshift(&r); + } + k += 1; + assert(!bn_is_zero(&v)); // assert GCD(x, prime) == 1 + } + + // s = s / 2**(k // BITS_PER_LIMB * BITS_PER_LIMB) + for (int i = 0; i < k / BITS_PER_LIMB; i++) { + bn_divide_base(&s, prime); + } + + // s = s / 2**(k % BITS_PER_LIMB) + for (int i = 0; i < k % BN_BITS_PER_LIMB; i++) { + bn_mult_half(&s, prime); + } + + bn_copy(&s, x); + + memzero(&u, sizeof(u)); + memzero(&v, sizeof(v)); + memzero(&r, sizeof(r)); + memzero(&s, sizeof(s)); +} +#endif + +#if USE_INVERSE_FAST +// x = 1/x % prime if x != 0 else 0 +// Assumes x is is_normalized +// Assumes GCD(x, prime) = 1 +// Guarantees x is normalized and fully reduced modulo prime +// Assumes prime is odd, normalized, 2**256 - 2**224 <= prime <= 2**256 +// The function has constant control flow but not constant memory access flow +// with regard to prime and x +static void bn_inverse_fast(bignum256* x, const bignum256* prime) { + // Custom constant time version of "The Almost Montgomery Inverse" from the + // section 3 of "Constant Time Modular Inversion" by Joppe W. Bos + // See http://www.joppebos.com/files/CTInversion.pdf + + /* + u = prime + v = x % prime + s = 1 + r = 0 + + k = 0 + while v != 1: + k += 1 + if is_even(u): # b1 + u = u // 2 + s = 2 * s + elif is_even(v): # b2 + v = v // 2 + r = 2 * r + elif v < u: # b3 + u = (u - v) // 2 + r = r + s + s = 2 * s + else: # b4 + v = (v - u) // 2 + s = r + s + r = 2 * r + + s = (s / 2**k) % prime + return s + */ + + bn_fast_mod(x, prime); + bn_mod(x, prime); + + bignum256 u = {0}, v = {0}, r = {0}, s = {0}; + bn_copy(prime, &u); + bn_copy(x, &v); + bn_one(&s); + bn_zero(&r); + + bignum256 zero = {0}; + bn_zero(&zero); + + int k = 0; + + int finished = 0, u_even = 0, v_even = 0, v_less_u = 0, b1 = 0, b2 = 0, b3 = 0, b4 = 0; + finished = 0; + + for(int i = 0; i < 2 * BN_LIMBS * BN_BITS_PER_LIMB; i++) { + finished = finished | -bn_is_one(&v); + u_even = -bn_is_even(&u); + v_even = -bn_is_even(&v); + v_less_u = -bn_is_less(&v, &u); + + b1 = ~finished & u_even; + b2 = ~finished & ~b1 & v_even; + b3 = ~finished & ~b1 & ~b2 & v_less_u; + b4 = ~finished & ~b1 & ~b2 & ~b3; + +// The ternary operator for pointers with constant control flow +// BN_INVERSE_FAST_TERNARY(c, t, f) = t if c else f +// Very nasty hack, sorry for that +#define BN_INVERSE_FAST_TERNARY(c, t, f) \ + ((void*)(((c) & (uintptr_t)(t)) | (~(c) & (uintptr_t)(f)))) + + bn_subtract( + BN_INVERSE_FAST_TERNARY(b3, &u, &v), + BN_INVERSE_FAST_TERNARY(b3 | b4, BN_INVERSE_FAST_TERNARY(b3, &v, &u), &zero), + BN_INVERSE_FAST_TERNARY(b3, &u, &v)); + + bn_add( + BN_INVERSE_FAST_TERNARY(b3, &r, &s), + BN_INVERSE_FAST_TERNARY(b3 | b4, BN_INVERSE_FAST_TERNARY(b3, &s, &r), &zero)); + bn_rshift(BN_INVERSE_FAST_TERNARY(b1 | b3, &u, &v)); + bn_lshift(BN_INVERSE_FAST_TERNARY(b1 | b3, &s, &r)); + + k = k - ~finished; + } + + // s = s / 2**(k // BITS_PER_LIMB * BITS_PER_LIMB) + for(int i = 0; i < 2 * BN_LIMBS; i++) { + // s = s / 2**BITS_PER_LIMB % prime if i < k // BITS_PER_LIMB else s + bn_copy(&s, &r); + bn_divide_base(&r, prime); + bn_cmov(&s, i < k / BN_BITS_PER_LIMB, &r, &s); + } + + // s = s / 2**(k % BITS_PER_LIMB) + for(int i = 0; i < BN_BITS_PER_LIMB; i++) { + // s = s / 2 % prime if i < k % BITS_PER_LIMB else s + bn_copy(&s, &r); + bn_mult_half(&r, prime); + bn_cmov(&s, i < k % BN_BITS_PER_LIMB, &r, &s); + } + + bn_cmov(x, bn_is_zero(x), x, &s); + + memzero(&u, sizeof(u)); + memzero(&v, sizeof(v)); + memzero(&r, sizeof(s)); + memzero(&s, sizeof(s)); +} +#endif + +#if false +// x = 1/x % prime if x != 0 else 0 +// Assumes x is is_normalized +// Assumes GCD(x, prime) = 1 +// Guarantees x is normalized and fully reduced modulo prime +// Assumes prime is odd, normalized, 2**256 - 2**224 <= prime <= 2**256 +static void bn_inverse_fast(bignum256 *x, const bignum256 *prime) { + // Custom constant time version of "The Almost Montgomery Inverse" from the + // section 3 of "Constant Time Modular Inversion" by Joppe W. Bos + // See http://www.joppebos.com/files/CTInversion.pdf + + /* + u = prime + v = x % prime + s = 1 + r = 0 + + k = 0 + while v != 1: + k += 1 + if is_even(u): # b1 + u = u // 2 + s = 2 * s + elif is_even(v): # b2 + v = v // 2 + r = 2 * r + elif v < u: # b3 + u = (u - v) // 2 + r = r + s + s = 2 * s + else: # b4 + v = (v - u) // 2 + s = r + s + r = 2 * r + + s = (s / 2**k) % prime + return s + */ + + bn_fast_mod(x, prime); + bn_mod(x, prime); + + bignum256 u = {0}, v = {0}, r = {0}, s = {0}; + bn_copy(prime, &u); + bn_copy(x, &v); + bn_one(&s); + bn_zero(&r); + + bignum256 zero = {0}; + bn_zero(&zero); + + int k = 0; + + uint32_t finished = 0, u_even = 0, v_even = 0, v_less_u = 0, b1 = 0, b2 = 0, + b3 = 0, b4 = 0; + finished = 0; + + bignum256 u_half = {0}, v_half = {0}, u_minus_v_half = {0}, v_minus_u_half = {0}, r_plus_s = {0}, r_twice = {0}, s_twice = {0}; + for (int i = 0; i < 2 * BN_LIMBS * BN_BITS_PER_LIMB; i++) { + finished = finished | bn_is_one(&v); + u_even = bn_is_even(&u); + v_even = bn_is_even(&v); + v_less_u = bn_is_less(&v, &u); + + b1 = (finished ^ 1) & u_even; + b2 = (finished ^ 1) & (b1 ^ 1) & v_even; + b3 = (finished ^ 1) & (b1 ^ 1) & (b2 ^ 1) & v_less_u; + b4 = (finished ^ 1) & (b1 ^ 1) & (b2 ^ 1) & (b3 ^ 1); + + // u_half = u // 2 + bn_copy(&u, &u_half); + bn_rshift(&u_half); + + // v_half = v // 2 + bn_copy(&v, &v_half); + bn_rshift(&v_half); + + // u_minus_v_half = (u - v) // 2 + bn_subtract(&u, &v, &u_minus_v_half); + bn_rshift(&u_minus_v_half); + + // v_minus_u_half = (v - u) // 2 + bn_subtract(&v, &u, &v_minus_u_half); + bn_rshift(&v_minus_u_half); + + // r_plus_s = r + s + bn_copy(&r, &r_plus_s); + bn_add(&r_plus_s, &s); + + // r_twice = 2 * r + bn_copy(&r, &r_twice); + bn_lshift(&r_twice); + + // s_twice = 2 * s + bn_copy(&s, &s_twice); + bn_lshift(&s_twice); + + bn_cmov(&u, b1, &u_half, &u); + bn_cmov(&u, b3, &u_minus_v_half, &u); + + bn_cmov(&v, b2, &v_half, &v); + bn_cmov(&v, b4, &v_minus_u_half, &v); + + bn_cmov(&r, b2 | b4, &r_twice, &r); + bn_cmov(&r, b3, &r_plus_s, &r); + + bn_cmov(&s, b1 | b3, &s_twice, &s); + bn_cmov(&s, b4, &r_plus_s, &s); + + k = k + (finished ^ 1); + } + + // s = s / 2**(k // BITS_PER_LIMB * BITS_PER_LIMB) + for (int i = 0; i < 2 * BN_LIMBS; i++) { + // s = s / 2**BITS_PER_LIMB % prime if i < k // BITS_PER_LIMB else s + bn_copy(&s, &r); + bn_divide_base(&r, prime); + bn_cmov(&s, i < k / BITS_PER_LIMB, &r, &s); + } + + // s = s / 2**(k % BITS_PER_LIMB) + for (int i = 0; i < BN_BITS_PER_LIMB; i++) { + // s = s / 2 % prime if i < k % BITS_PER_LIMB else s + bn_copy(&s, &r); + bn_mult_half(&r, prime); + bn_cmov(&s, i < k % BN_BITS_PER_LIMB, &r, &s); + } + + bn_cmov(x, bn_is_zero(x), x, &s); + + memzero(&u, sizeof(u)); + memzero(&v, sizeof(v)); + memzero(&r, sizeof(r)); + memzero(&s, sizeof(s)); + memzero(&u_half, sizeof(u_half)); + memzero(&v_half, sizeof(v_half)); + memzero(&u_minus_v_half, sizeof(u_minus_v_half)); + memzero(&v_minus_u_half, sizeof(v_minus_u_half)); + memzero(&r_twice, sizeof(r_twice)); + memzero(&s_twice, sizeof(s_twice)); + memzero(&r_plus_s, sizeof(r_plus_s)); +} +#endif + +// Normalizes x +// Assumes x < 2**261 == 2**(LIMBS * BITS_PER_LIMB) +// Guarantees x is normalized +void bn_normalize(bignum256* x) { + uint32_t acc = 0; + + for(int i = 0; i < BN_LIMBS; i++) { + acc += x->val[i]; + // acc doesn't overflow 32 bits + // Proof: + // acc + x[i] + // <= (2**(32 - BITS_PER_LIMB) - 1) + (2**BITS_PER_LIMB - 1) + // == 7 + 2**29 - 1 < 2**32 + + x->val[i] = acc & BN_LIMB_MASK; + acc >>= (BN_BITS_PER_LIMB); + // acc <= 7 == 2**(32 - BITS_PER_LIMB) - 1 + } +} + +// x = x + y +// Assumes x, y are normalized, x + y < 2**(LIMBS*BITS_PER_LIMB) == 2**261 +// Guarantees x is normalized +// Works properly even if &x == &y +void bn_add(bignum256* x, const bignum256* y) { + uint32_t acc = 0; + for(int i = 0; i < BN_LIMBS; i++) { + acc += x->val[i] + y->val[i]; + // acc doesn't overflow 32 bits + // Proof: + // acc + x[i] + y[i] + // <= (2**(32 - BITS_PER_LIMB) - 1) + 2 * (2**BITS_PER_LIMB - 1) + // == (2**(32 - BITS_PER_LIMB) - 1) + 2**(BITS_PER_LIMB + 1) - 2 + // == 7 + 2**30 - 2 < 2**32 + + x->val[i] = acc & BN_LIMB_MASK; + acc >>= BN_BITS_PER_LIMB; + // acc <= 7 == 2**(32 - BITS_PER_LIMB) - 1 + + // acc == x[:i + 1] + y[:i + 1] >> BITS_PER_LIMB * (i + 1) + } + + // assert(acc == 0); // assert x + y < 2**261 + // acc == 0 + // Proof: + // acc == x[:LIMBS] + y[:LIMBS] >> LIMBS * BITS_PER_LIMB + // == x + y >> LIMBS * BITS_PER_LIMB + // <= 2**(LIMBS * BITS_PER_LIMB) - 1 >> LIMBS * BITS_PER_LIMB == 0 +} + +// x = x + y % prime +// Assumes x, y are normalized +// Guarantees x is normalized and partly reduced modulo prime +// Assumes prime is normalized and 2^256 - 2^224 <= prime <= 2^256 +void bn_addmod(bignum256* x, const bignum256* y, const bignum256* prime) { + for(int i = 0; i < BN_LIMBS; i++) { + x->val[i] += y->val[i]; + // x[i] doesn't overflow 32 bits + // Proof: + // x[i] + y[i] + // <= 2 * (2**BITS_PER_LIMB - 1) + // == 2**30 - 2 < 2**32 + } + + bn_fast_mod(x, prime); +} + +// x = x + y +// Assumes x is normalized +// Assumes y <= 2**32 - 2**29 == 2**32 - 2**BITS_PER_LIMB and +// x + y < 2**261 == 2**(LIMBS * BITS_PER_LIMB) +// Guarantees x is normalized +void bn_addi(bignum256* x, uint32_t y) { + // assert(y <= 3758096384); // assert y <= 2**32 - 2**29 + uint32_t acc = y; + + for(int i = 0; i < BN_LIMBS; i++) { + acc += x->val[i]; + // acc doesn't overflow 32 bits + // Proof: + // if i == 0: + // acc + x[i] == y + x[0] + // <= (2**32 - 2**BITS_PER_LIMB) + (2**BITS_PER_LIMB - 1) + // == 2**32 - 1 < 2**32 + // else: + // acc + x[i] + // <= (2**(32 - BITS_PER_LIMB) - 1) + (2**BITS_PER_LIMB - 1) + // == 7 + 2**29 - 1 < 2**32 + + x->val[i] = acc & BN_LIMB_MASK; + acc >>= (BN_BITS_PER_LIMB); + // acc <= 7 == 2**(32 - BITS_PER_LIMB) - 1 + + // acc == x[:i + 1] + y >> BITS_PER_LIMB * (i + 1) + } + + // assert(acc == 0); // assert x + y < 2**261 + // acc == 0 + // Proof: + // acc == x[:LIMBS] + y << LIMBS * BITS_PER_LIMB + // == x + y << LIMBS * BITS_PER_LIMB + // <= 2**(LIMBS + BITS_PER_LIMB) - 1 << LIMBS * BITS_PER_LIMB + // == 0 +} + +// x = x - y % prime +// Explicitly x = x + prime - y +// Assumes x, y are normalized +// Assumes y < prime[0], x + prime - y < 2**261 == 2**(LIMBS * BITS_PER_LIMB) +// Guarantees x is normalized +// If x is fully reduced modulo prime, +// guarantess x will be partly reduced modulo prime +// Assumes prime is nonzero and normalized +void bn_subi(bignum256* x, uint32_t y, const bignum256* prime) { + assert(y < prime->val[0]); + + // x = x + prime - y + + uint32_t acc = -y; + for(int i = 0; i < BN_LIMBS; i++) { + acc += x->val[i] + prime->val[i]; + // acc neither overflows 32 bits nor underflows 0 + // Proof: + // acc + x[i] + prime[i] + // <= (2**(32 - BITS_PER_LIMB) - 1) + 2 * (2**BITS_PER_LIMB - 1) + // <= 7 + 2**30 - 2 < 2**32 + // acc + x[i] + prime[i] + // >= -y + prime[0] >= 0 + + x->val[i] = acc & BN_LIMB_MASK; + acc >>= BN_BITS_PER_LIMB; + // acc <= 7 == 2**(32 - BITS_PER_LIMB) - 1 + + // acc == x[:i + 1] + prime[:i + 1] - y >> BITS_PER_LIMB * (i + 1) + } + + // assert(acc == 0); // assert x + prime - y < 2**261 + // acc == 0 + // Proof: + // acc == x[:LIMBS] + prime[:LIMBS] - y >> BITS_PER_LIMB * LIMBS + // == x + prime - y >> BITS_PER_LIMB * LIMBS + // <= 2**(LIMBS * BITS_PER_LIMB) - 1 >> BITS_PER_LIMB * LIMBS == 0 +} + +// res = x - y % prime +// Explicitly res = x + (2 * prime - y) +// Assumes x, y are normalized, y is partly reduced +// Assumes x + 2 * prime - y < 2**261 == 2**(BITS_PER_LIMB * LIMBS) +// Guarantees res is normalized +// Assumes prime is nonzero and normalized +void bn_subtractmod(const bignum256* x, const bignum256* y, bignum256* res, const bignum256* prime) { + // res = x + (2 * prime - y) + + uint32_t acc = 1; + + for(int i = 0; i < BN_LIMBS; i++) { + acc += (BN_BASE - 1) + x->val[i] + 2 * prime->val[i] - y->val[i]; + // acc neither overflows 32 bits nor underflows 0 + // Proof: + // acc + (BASE - 1) + x[i] + 2 * prime[i] - y[i] + // >= (BASE - 1) - y[i] + // == (2**BITS_PER_LIMB - 1) - (2**BITS_PER_LIMB - 1) == 0 + // acc + (BASE - 1) + x[i] + 2 * prime[i] - y[i] + // <= acc + (BASE - 1) + x[i] + 2 * prime[i] + // <= (2**(32 - BITS_PER_LIMB) - 1) + (2**BITS_PER_LIMB - 1) + + // (2**BITS_PER_LIMB - 1) + 2 * (2**BITS_PER_LIMB - 1) + // <= (2**(32 - BITS_PER_LIMB) - 1) + 4 * (2**BITS_PER_LIMB - 1) + // == 7 + 4 * 2**29 - 4 == 2**31 + 3 < 2**32 + + res->val[i] = acc & (BN_BASE - 1); + acc >>= BN_BITS_PER_LIMB; + // acc <= 7 == 2**(32 - BITS_PER_LIMB) - 1 + + // acc == 2**(BITS_PER_LIMB * (i + 1)) + x[:i+1] - y[:i+1] + 2*prime[:i+1] + // >> BITS_PER_LIMB * (i+1) + } + + // assert(acc == 1); // assert x + 2 * prime - y < 2**261 + + // clang-format off + // acc == 1 + // Proof: + // acc == 2**(BITS_PER_LIMB * LIMBS) + x[:LIMBS] - y[:LIMBS] + 2 * prime[:LIMBS] >> BITS_PER_LIMB * LIMBS + // == 2**(BITS_PER_LIMB * LIMBS) + x - y + 2 * prime >> BITS_PER_LIMB * LIMBS + // == 2**(BITS_PER_LIMB * LIMBS) + x + (2 * prime - y) >> BITS_PER_LIMB * LIMBS + // <= 2**(BITS_PER_LIMB * LIMBS) + 2**(BITS_PER_LIMB * LIMBS) - 1 >> BITS_PER_LIMB * LIMBS + // <= 2 * 2**(BITS_PER_LIMB * LIMBS) - 1 >> BITS_PER_LIMB * LIMBS + // == 1 + + // acc == 2**(BITS_PER_LIMB * LIMBS) + x[:LIMBS] - y[:LIMBS] + 2 * prime[:LIMBS] >> BITS_PER_LIMB * LIMBS + // == 2**(BITS_PER_LIMB * LIMBS) + x - y + 2 * prime >> BITS_PER_LIMB * LIMBS + // == 2**(BITS_PER_LIMB * LIMBS) + x + (2 * prime - y) >> BITS_PER_LIMB * LIMBS + // >= 2**(BITS_PER_LIMB * LIMBS) + 0 + 1 >> BITS_PER_LIMB * LIMBS + // == 1 + // clang-format on +} + +// res = x - y +// Assumes x, y are normalized and x >= y +// Guarantees res is normalized +// Works properly even if &x == &y or &x == &res or &y == &res or +// &x == &y == &res +void bn_subtract(const bignum256* x, const bignum256* y, bignum256* res) { + uint32_t acc = 1; + for(int i = 0; i < BN_LIMBS; i++) { + acc += (BN_BASE - 1) + x->val[i] - y->val[i]; + // acc neither overflows 32 bits nor underflows 0 + // Proof: + // acc + (BASE - 1) + x[i] - y[i] + // >= (BASE - 1) - y == (2**BITS_PER_LIMB - 1) - (2**BITS_PER_LIMB - 1) + // == 0 + // acc + (BASE - 1) + x[i] - y[i] + // <= acc + (BASE - 1) + x[i] + // <= (2**(32 - BITS_PER_LIMB) - 1) + (2**BITS_PER_LIMB - 1) + + // (2**BITS_PER_LIMB - 1) + // == 7 + 2 * 2**29 < 2 **32 + + res->val[i] = acc & BN_LIMB_MASK; + acc >>= BN_BITS_PER_LIMB; + // acc <= 7 == 2**(32 - BITS_PER_LIMB) - 1 + + // acc == 2**(BITS_PER_LIMB * (i + 1)) + x[:i + 1] - y[:i + 1] + // >> BITS_PER_LIMB * (i + 1) + } + + // assert(acc == 1); // assert x >= y + + // clang-format off + // acc == 1 + // Proof: + // acc == 2**(BITS_PER_LIMB * LIMBS) + x[:LIMBS] - y[:LIMBS] >> BITS_PER_LIMB * LIMBS + // == 2**(BITS_PER_LIMB * LIMBS) + x - y >> BITS_PER_LIMB * LIMBS + // == 2**(BITS_PER_LIMB * LIMBS) + x >> BITS_PER_LIMB * LIMBS + // <= 2**(BITS_PER_LIMB * LIMBS) + 2**(BITS_PER_LIMB * LIMBS) - 1 >> BITS_PER_LIMB * LIMBS + // <= 2 * 2**(BITS_PER_LIMB * LIMBS) - 1 >> BITS_PER_LIMB * LIMBS + // == 1 + + // acc == 2**(BITS_PER_LIMB * LIMBS) + x[:LIMBS] - y[:LIMBS] >> BITS_PER_LIMB * LIMBS + // == 2**(BITS_PER_LIMB * LIMBS) + x - y >> BITS_PER_LIMB * LIMBS + // >= 2**(BITS_PER_LIMB * LIMBS) >> BITS_PER_LIMB * LIMBS + // == 1 +} + +// q = x // d, r = x % d +// Assumes x is normalized, 1 <= d <= 61304 +// Guarantees q is normalized +void bn_long_division(bignum256 *x, uint32_t d, bignum256 *q, uint32_t *r) { + assert(1 <= d && d < 61304); + + uint32_t acc = 0; + + *r = x->val[BN_LIMBS - 1] % d; + q->val[BN_LIMBS - 1] = x->val[BN_LIMBS - 1] / d; + + for (int i = BN_LIMBS - 2; i >= 0; i--) { + acc = *r * (BN_BASE % d) + x->val[i]; + // acc doesn't overflow 32 bits + // Proof: + // r * (BASE % d) + x[i] + // <= (d - 1) * (d - 1) + (2**BITS_PER_LIMB - 1) + // == d**2 - 2*d + 2**BITS_PER_LIMB + // == 61304**2 - 2 * 61304 + 2**29 + // == 3758057808 + 2**29 < 2**32 + + q->val[i] = *r * (BN_BASE / d) + (acc / d); + // q[i] doesn't overflow 32 bits + // Proof: + // r * (BASE // d) + (acc // d) + // <= (d - 1) * (2**BITS_PER_LIMB / d) + + // ((d**2 - 2*d + 2**BITS_PER_LIMB) / d) + // <= (d - 1) * (2**BITS_PER_LIMB / d) + (d - 2 + 2**BITS_PER_LIMB / d) + // == (d - 1 + 1) * (2**BITS_PER_LIMB / d) + d - 2 + // == 2**BITS_PER_LIMB + d - 2 <= 2**29 + 61304 < 2**32 + + // q[i] == (r * BASE + x[i]) // d + // Proof: + // q[i] == r * (BASE // d) + (acc // d) + // == r * (BASE // d) + (r * (BASE % d) + x[i]) // d + // == (r * d * (BASE // d) + r * (BASE % d) + x[i]) // d + // == (r * (d * (BASE // d) + (BASE % d)) + x[i]) // d + // == (r * BASE + x[i]) // d + + // q[i] < 2**BITS_PER_LIMB + // Proof: + // q[i] == (r * BASE + x[i]) // d + // <= ((d - 1) * 2**BITS_PER_LIMB + (2**BITS_PER_LIMB - 1)) / d + // == (d * 2**BITS_PER_LIMB - 1) / d == 2**BITS_PER_LIMB - 1 / d + // < 2**BITS_PER_LIMB + + *r = acc % d; + // r == (r * BASE + x[i]) % d + // Proof: + // r == acc % d == (r * (BASE % d) + x[i]) % d + // == (r * BASE + x[i]) % d + + // x[:i] == q[:i] * d + r + } +} + +// x = x // 58, r = x % 58 +// Assumes x is normalized +// Guarantees x is normalized +void bn_divmod58(bignum256 *x, uint32_t *r) { bn_long_division(x, 58, x, r); } + +// x = x // 1000, r = x % 1000 +// Assumes x is normalized +// Guarantees x is normalized +void bn_divmod1000(bignum256 *x, uint32_t *r) { + bn_long_division(x, 1000, x, r); +} + +// x = x // 10, r = x % 10 +// Assumes x is normalized +// Guarantees x is normalized +void bn_divmod10(bignum256 *x, uint32_t *r) { bn_long_division(x, 10, x, r); } + +// Formats amount +// Assumes amount is normalized +// Assumes prefix and suffix are null-terminated strings +// Assumes output is an array of length output_length +// The function doesn't have neither constant control flow nor constant memory +// access flow with regard to any its argument +size_t bn_format(const bignum256 *amount, const char *prefix, const char *suffix, unsigned int decimals, int exponent, bool trailing, char thousands, char *output, size_t output_length) { + +/* + Python prototype of the function: + + def format(amount, prefix, suffix, decimals, exponent, trailing, thousands): + if exponent >= 0: + amount *= 10**exponent + else: + amount //= 10 ** (-exponent) + + d = pow(10, decimals) + + integer_part = amount // d + integer_str = f"{integer_part:,}".replace(",", thousands or "") + + if decimals: + decimal_part = amount % d + decimal_str = f".{decimal_part:0{decimals}d}" + if not trailing: + decimal_str = decimal_str.rstrip("0").rstrip(".") + else: + decimal_str = "" + + return prefix + integer_str + decimal_str + suffix +*/ + +// Auxiliary macro for bn_format +// If enough space adds one character to output starting from the end +#define BN_FORMAT_ADD_OUTPUT_CHAR(c) \ + { \ + --position; \ + if (output <= position && position < output + output_length) { \ + *position = (c); \ + } else { \ + memset(output, '\0', output_length); \ + return 0; \ + } \ + } + + bignum256 temp = {0}; + bn_copy(amount, &temp); + uint32_t digit = 0; + + char *position = output + output_length; + + // Add string ending character + BN_FORMAT_ADD_OUTPUT_CHAR('\0'); + + // Add suffix + size_t suffix_length = suffix ? strlen(suffix) : 0; + for (int i = suffix_length - 1; i >= 0; --i) + BN_FORMAT_ADD_OUTPUT_CHAR(suffix[i]) + + // amount //= 10**exponent + for (; exponent < 0; ++exponent) { + // if temp == 0, there is no need to divide it by 10 anymore + if (bn_is_zero(&temp)) { + exponent = 0; + break; + } + bn_divmod10(&temp, &digit); + } + + // exponent >= 0 && decimals >= 0 + + bool fractional_part = false; // is fractional-part of amount present + + { // Add fractional-part digits of amount + // Add trailing zeroes + unsigned int trailing_zeros = decimals < (unsigned int) exponent ? decimals : (unsigned int) exponent; + // When casting a negative int to unsigned int, UINT_MAX is added to the int before + // Since exponent >= 0, the value remains unchanged + decimals -= trailing_zeros; + exponent -= trailing_zeros; + + if (trailing && trailing_zeros) { + fractional_part = true; + for (; trailing_zeros > 0; --trailing_zeros) + BN_FORMAT_ADD_OUTPUT_CHAR('0') + } + + // exponent == 0 || decimals == 0 + + // Add significant digits and leading zeroes + for (; decimals > 0; --decimals) { + bn_divmod10(&temp, &digit); + + if (fractional_part || digit || trailing) { + fractional_part = true; + BN_FORMAT_ADD_OUTPUT_CHAR('0' + digit) + } + else if (bn_is_zero(&temp)) { + // We break since the remaining digits are zeroes and fractional_part == trailing == false + decimals = 0; + break; + } + } + // decimals == 0 + } + + if (fractional_part) { + BN_FORMAT_ADD_OUTPUT_CHAR('.') + } + + { // Add integer-part digits of amount + // Add trailing zeroes + int digits = 0; + if (!bn_is_zero(&temp)) { + for (; exponent > 0; --exponent) { + ++digits; + BN_FORMAT_ADD_OUTPUT_CHAR('0') + if (thousands != 0 && digits % 3 == 0) { + BN_FORMAT_ADD_OUTPUT_CHAR(thousands) + } + } + } + // decimals == 0 && exponent == 0 + + // Add significant digits + bool is_zero = false; + do { + ++digits; + bn_divmod10(&temp, &digit); + is_zero = bn_is_zero(&temp); + BN_FORMAT_ADD_OUTPUT_CHAR('0' + digit) + if (thousands != 0 && !is_zero && digits % 3 == 0) { + BN_FORMAT_ADD_OUTPUT_CHAR(thousands) + } + } while (!is_zero); + } + + // Add prefix + size_t prefix_length = prefix ? strlen(prefix) : 0; + for (int i = prefix_length - 1; i >= 0; --i) + BN_FORMAT_ADD_OUTPUT_CHAR(prefix[i]) + + // Move formatted amount to the start of output + int length = output - position + output_length; + memmove(output, position, length); + return length - 1; +} + +#if USE_BN_PRINT +// Prints x in hexadecimal +// Assumes x is normalized and x < 2**256 +void bn_print(const bignum256 *x) { + printf("%06x", x->val[8]); + printf("%08x", ((x->val[7] << 3) | (x->val[6] >> 26))); + printf("%07x", ((x->val[6] << 2) | (x->val[5] >> 27)) & 0x0FFFFFFF); + printf("%07x", ((x->val[5] << 1) | (x->val[4] >> 28)) & 0x0FFFFFFF); + printf("%07x", x->val[4] & 0x0FFFFFFF); + printf("%08x", ((x->val[3] << 3) | (x->val[2] >> 26))); + printf("%07x", ((x->val[2] << 2) | (x->val[1] >> 27)) & 0x0FFFFFFF); + printf("%07x", ((x->val[1] << 1) | (x->val[0] >> 28)) & 0x0FFFFFFF); + printf("%07x", x->val[0] & 0x0FFFFFFF); +} + +// Prints comma separated list of limbs of x +void bn_print_raw(const bignum256 *x) { + for (int i = 0; i < BN_LIMBS - 1; i++) { + printf("0x%08x, ", x->val[i]); + } + printf("0x%08x", x->val[BN_LIMBS - 1]); +} +#endif + +#if USE_INVERSE_FAST +void bn_inverse(bignum256 *x, const bignum256 *prime) { + bn_inverse_fast(x, prime); +} +#else +void bn_inverse(bignum256 *x, const bignum256 *prime) { + bn_inverse_slow(x, prime); +} +#endif diff --git a/applications/external/flipbip/lib/crypto/bignum.h b/applications/external/flipbip/lib/crypto/bignum.h new file mode 100644 index 000000000..858613401 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/bignum.h @@ -0,0 +1,195 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * Copyright (c) 2016 Alex Beregszaszi + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BIGNUM_H__ +#define __BIGNUM_H__ + +#include +#include +#include + +#include "options.h" + +#define BN_LIMBS 9 +#define BN_BITS_PER_LIMB 29 +#define BN_BASE (1u << BN_BITS_PER_LIMB) +#define BN_LIMB_MASK ((1u << BN_BITS_PER_LIMB) - 1) +#define BN_EXTRA_BITS (32 - BN_BITS_PER_LIMB) +#define BN_BITS_LAST_LIMB (256 - (BN_LIMBS - 1) * BN_BITS_PER_LIMB) + +// Represents the number sum([val[i] * 2**(29*i) for i in range(9)) +typedef struct { + uint32_t val[BN_LIMBS]; +} bignum256; + +static inline uint32_t read_be(const uint8_t* data) { + return (((uint32_t)data[0]) << 24) | (((uint32_t)data[1]) << 16) | (((uint32_t)data[2]) << 8) | + (((uint32_t)data[3])); +} + +static inline void write_be(uint8_t* data, uint32_t x) { + data[0] = x >> 24; + data[1] = x >> 16; + data[2] = x >> 8; + data[3] = x; +} + +static inline uint32_t read_le(const uint8_t* data) { + return (((uint32_t)data[3]) << 24) | (((uint32_t)data[2]) << 16) | (((uint32_t)data[1]) << 8) | + (((uint32_t)data[0])); +} + +static inline void write_le(uint8_t* data, uint32_t x) { + data[3] = x >> 24; + data[2] = x >> 16; + data[1] = x >> 8; + data[0] = x; +} + +void bn_read_be(const uint8_t* in_number, bignum256* out_number); +void bn_write_be(const bignum256* in_number, uint8_t* out_number); +void bn_read_le(const uint8_t* in_number, bignum256* out_number); +void bn_write_le(const bignum256* in_number, uint8_t* out_number); +void bn_read_uint32(uint32_t in_number, bignum256* out_number); +void bn_read_uint64(uint64_t in_number, bignum256* out_number); +int bn_bitcount(const bignum256* x); +unsigned int bn_digitcount(const bignum256* x); +void bn_zero(bignum256* x); +void bn_one(bignum256* x); +int bn_is_zero(const bignum256* x); +int bn_is_one(const bignum256* x); +int bn_is_less(const bignum256* x, const bignum256* y); +int bn_is_equal(const bignum256* x, const bignum256* y); +void bn_cmov( + bignum256* res, + volatile uint32_t cond, + const bignum256* truecase, + const bignum256* falsecase); +void bn_cnegate(volatile uint32_t cond, bignum256* x, const bignum256* prime); +void bn_lshift(bignum256* x); +void bn_rshift(bignum256* x); +void bn_setbit(bignum256* x, uint16_t i); +void bn_clearbit(bignum256* x, uint16_t i); +uint32_t bn_testbit(const bignum256* x, uint16_t i); +void bn_xor(bignum256* res, const bignum256* x, const bignum256* y); +void bn_mult_half(bignum256* x, const bignum256* prime); +void bn_mult_k(bignum256* x, uint8_t k, const bignum256* prime); +void bn_mod(bignum256* x, const bignum256* prime); +void bn_multiply(const bignum256* k, bignum256* x, const bignum256* prime); +void bn_fast_mod(bignum256* x, const bignum256* prime); +void bn_power_mod(const bignum256* x, const bignum256* e, const bignum256* prime, bignum256* res); +void bn_sqrt(bignum256* x, const bignum256* prime); +uint32_t inverse_mod_power_two(uint32_t a, uint32_t n); +void bn_divide_base(bignum256* x, const bignum256* prime); +void bn_normalize(bignum256* x); +void bn_add(bignum256* x, const bignum256* y); +void bn_addmod(bignum256* x, const bignum256* y, const bignum256* prime); +void bn_addi(bignum256* x, uint32_t y); +void bn_subi(bignum256* x, uint32_t y, const bignum256* prime); +void bn_subtractmod(const bignum256* x, const bignum256* y, bignum256* res, const bignum256* prime); +void bn_subtract(const bignum256* x, const bignum256* y, bignum256* res); +void bn_long_division(bignum256* x, uint32_t d, bignum256* q, uint32_t* r); +void bn_divmod58(bignum256* x, uint32_t* r); +void bn_divmod1000(bignum256* x, uint32_t* r); +void bn_inverse(bignum256* x, const bignum256* prime); +size_t bn_format( + const bignum256* amount, + const char* prefix, + const char* suffix, + unsigned int decimals, + int exponent, + bool trailing, + char thousands, + char* output, + size_t output_length); + +// Returns (uint32_t) in_number +// Assumes in_number < 2**32 +// Assumes in_number is normalized +static inline uint32_t bn_write_uint32(const bignum256* in_number) { + return in_number->val[0] | (in_number->val[1] << BN_BITS_PER_LIMB); +} + +// Returns (uint64_t) in_number +// Assumes in_number < 2**64 +// Assumes in_number is normalized +static inline uint64_t bn_write_uint64(const bignum256* in_number) { + uint64_t acc; + acc = in_number->val[2]; + acc <<= BN_BITS_PER_LIMB; + acc |= in_number->val[1]; + acc <<= BN_BITS_PER_LIMB; + acc |= in_number->val[0]; + return acc; +} + +// y = x +static inline void bn_copy(const bignum256* x, bignum256* y) { + *y = *x; +} + +// Returns x % 2 == 0 +static inline int bn_is_even(const bignum256* x) { + return (x->val[0] & 1) == 0; +} + +// Returns x % 2 == 0 +static inline int bn_is_odd(const bignum256* x) { + return (x->val[0] & 1) == 1; +} + +static inline size_t bn_format_uint64( + uint64_t amount, + const char* prefix, + const char* suffix, + unsigned int decimals, + int exponent, + bool trailing, + char thousands, + char* output, + size_t output_length) { + bignum256 bn_amount; + bn_read_uint64(amount, &bn_amount); + + return bn_format( + &bn_amount, prefix, suffix, decimals, exponent, trailing, thousands, output, output_length); +} + +static inline size_t bn_format_amount( + uint64_t amount, + const char* prefix, + const char* suffix, + unsigned int decimals, + char* output, + size_t output_length) { + return bn_format_uint64( + amount, prefix, suffix, decimals, 0, false, ',', output, output_length); +} + +#if USE_BN_PRINT +void bn_print(const bignum256* x); +void bn_print_raw(const bignum256* x); +#endif + +#endif diff --git a/applications/external/flipbip/lib/crypto/bip32.c b/applications/external/flipbip/lib/crypto/bip32.c new file mode 100644 index 000000000..09f00d60e --- /dev/null +++ b/applications/external/flipbip/lib/crypto/bip32.c @@ -0,0 +1,885 @@ +/** + * Copyright (c) 2013-2016 Tomas Dzetkulic + * Copyright (c) 2013-2016 Pavol Rusnak + * Copyright (c) 2015-2016 Jochen Hoenicke + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include + +#include "address.h" +#include "aes/aes.h" +#include "base58.h" +#include "bignum.h" +#include "bip32.h" +#include "cardano.h" +#include "curves.h" +#include "ecdsa.h" +#include "ed25519_donna/ed25519_sha3.h" +#include "ed25519_donna/ed25519.h" +#include "hmac.h" +#include "nist256p1.h" +#include "secp256k1.h" +#include "sha2.h" +#include "sha3.h" +#if USE_KECCAK +#include "ed25519_donna/ed25519_keccak.h" +#endif +#if USE_NEM +#include "nem.h" +#endif +#include "memzero.h" + +const curve_info ed25519_info = { + .bip32_name = ED25519_SEED_NAME, + .params = NULL, + .hasher_base58 = HASHER_SHA2D, + .hasher_sign = HASHER_SHA2D, + .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_script = HASHER_SHA2, +}; + +const curve_info ed25519_sha3_info = { + .bip32_name = "ed25519-sha3 seed", + .params = NULL, + .hasher_base58 = HASHER_SHA2D, + .hasher_sign = HASHER_SHA2D, + .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_script = HASHER_SHA2, +}; + +#if USE_KECCAK +const curve_info ed25519_keccak_info = { + .bip32_name = "ed25519-keccak seed", + .params = NULL, + .hasher_base58 = HASHER_SHA2D, + .hasher_sign = HASHER_SHA2D, + .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_script = HASHER_SHA2, +}; +#endif + +const curve_info curve25519_info = { + .bip32_name = "curve25519 seed", + .params = NULL, + .hasher_base58 = HASHER_SHA2D, + .hasher_sign = HASHER_SHA2D, + .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_script = HASHER_SHA2, +}; + +int hdnode_from_xpub( + uint32_t depth, + uint32_t child_num, + const uint8_t* chain_code, + const uint8_t* public_key, + const char* curve, + HDNode* out) { + const curve_info* info = get_curve_by_name(curve); + if(info == 0) { + return 0; + } + if(public_key[0] != 0x02 && public_key[0] != 0x03) { // invalid pubkey + return 0; + } + out->curve = info; + out->depth = depth; + out->child_num = child_num; + memcpy(out->chain_code, chain_code, 32); + memzero(out->private_key, 32); + memzero(out->private_key_extension, 32); + memcpy(out->public_key, public_key, 33); + return 1; +} + +int hdnode_from_xprv( + uint32_t depth, + uint32_t child_num, + const uint8_t* chain_code, + const uint8_t* private_key, + const char* curve, + HDNode* out) { + bool failed = false; + const curve_info* info = get_curve_by_name(curve); + if(info == 0) { + failed = true; + } else if(info->params) { + bignum256 a = {0}; + bn_read_be(private_key, &a); + if(bn_is_zero(&a)) { // == 0 + failed = true; + } else { + if(!bn_is_less(&a, &info->params->order)) { // >= order + failed = true; + } + } + memzero(&a, sizeof(a)); + } + + if(failed) { + return 0; + } + + out->curve = info; + out->depth = depth; + out->child_num = child_num; + memcpy(out->chain_code, chain_code, 32); + memcpy(out->private_key, private_key, 32); + memzero(out->public_key, sizeof(out->public_key)); + memzero(out->private_key_extension, sizeof(out->private_key_extension)); + return 1; +} + +int hdnode_from_seed(const uint8_t* seed, int seed_len, const char* curve, HDNode* out) { + static CONFIDENTIAL uint8_t I[32 + 32]; + memzero(out, sizeof(HDNode)); + out->depth = 0; + out->child_num = 0; + out->curve = get_curve_by_name(curve); + if(out->curve == 0) { + return 0; + } + static CONFIDENTIAL HMAC_SHA512_CTX ctx; + hmac_sha512_Init(&ctx, (const uint8_t*)out->curve->bip32_name, strlen(out->curve->bip32_name)); + hmac_sha512_Update(&ctx, seed, seed_len); + hmac_sha512_Final(&ctx, I); + + if(out->curve->params) { + bignum256 a = {0}; + while(true) { + bn_read_be(I, &a); + if(!bn_is_zero(&a) // != 0 + && bn_is_less(&a, &out->curve->params->order)) { // < order + break; + } + hmac_sha512_Init( + &ctx, (const uint8_t*)out->curve->bip32_name, strlen(out->curve->bip32_name)); + hmac_sha512_Update(&ctx, I, sizeof(I)); + hmac_sha512_Final(&ctx, I); + } + memzero(&a, sizeof(a)); + } + memcpy(out->private_key, I, 32); + memcpy(out->chain_code, I + 32, 32); + memzero(out->public_key, sizeof(out->public_key)); + memzero(I, sizeof(I)); + return 1; +} + +uint32_t hdnode_fingerprint(HDNode* node) { + uint8_t digest[32] = {0}; + uint32_t fingerprint = 0; + + hdnode_fill_public_key(node); + hasher_Raw(node->curve->hasher_pubkey, node->public_key, 33, digest); + fingerprint = ((uint32_t)digest[0] << 24) + (digest[1] << 16) + (digest[2] << 8) + digest[3]; + memzero(digest, sizeof(digest)); + return fingerprint; +} + +int hdnode_private_ckd_bip32(HDNode* inout, uint32_t i) { + static CONFIDENTIAL uint8_t data[1 + 32 + 4]; + static CONFIDENTIAL uint8_t I[32 + 32]; + static CONFIDENTIAL bignum256 a, b; + +#if USE_CARDANO + if(inout->curve == &ed25519_cardano_info) { + return 0; + } +#endif + + if(i & 0x80000000) { // private derivation + data[0] = 0; + memcpy(data + 1, inout->private_key, 32); + } else { // public derivation + if(!inout->curve->params) { + return 0; + } + if(hdnode_fill_public_key(inout) != 0) { + return 0; + } + memcpy(data, inout->public_key, 33); + } + write_be(data + 33, i); + + bn_read_be(inout->private_key, &a); + + static CONFIDENTIAL HMAC_SHA512_CTX ctx; + hmac_sha512_Init(&ctx, inout->chain_code, 32); + hmac_sha512_Update(&ctx, data, sizeof(data)); + hmac_sha512_Final(&ctx, I); + + if(inout->curve->params) { + while(true) { + bool failed = false; + bn_read_be(I, &b); + if(!bn_is_less(&b, &inout->curve->params->order)) { // >= order + failed = true; + } else { + bn_add(&b, &a); + bn_mod(&b, &inout->curve->params->order); + if(bn_is_zero(&b)) { + failed = true; + } + } + + if(!failed) { + bn_write_be(&b, inout->private_key); + break; + } + + data[0] = 1; + memcpy(data + 1, I + 32, 32); + hmac_sha512_Init(&ctx, inout->chain_code, 32); + hmac_sha512_Update(&ctx, data, sizeof(data)); + hmac_sha512_Final(&ctx, I); + } + } else { + memcpy(inout->private_key, I, 32); + } + + memcpy(inout->chain_code, I + 32, 32); + inout->depth++; + inout->child_num = i; + memzero(inout->public_key, sizeof(inout->public_key)); + + // making sure to wipe our memory + memzero(&a, sizeof(a)); + memzero(&b, sizeof(b)); + memzero(I, sizeof(I)); + memzero(data, sizeof(data)); + return 1; +} + +int hdnode_private_ckd(HDNode* inout, uint32_t i) { +#if USE_CARDANO + if(inout->curve == &ed25519_cardano_info) { + return hdnode_private_ckd_cardano(inout, i); + } else +#endif + { + return hdnode_private_ckd_bip32(inout, i); + } +} + +int hdnode_public_ckd_cp( + const ecdsa_curve* curve, + const curve_point* parent, + const uint8_t* parent_chain_code, + uint32_t i, + curve_point* child, + uint8_t* child_chain_code) { + uint8_t data[(1 + 32) + 4] = {0}; + uint8_t I[32 + 32] = {0}; + bignum256 c = {0}; + + if(i & 0x80000000) { // private derivation + return 0; + } + + data[0] = 0x02 | (parent->y.val[0] & 0x01); + bn_write_be(&parent->x, data + 1); + write_be(data + 33, i); + + while(true) { + hmac_sha512(parent_chain_code, 32, data, sizeof(data), I); + bn_read_be(I, &c); + if(bn_is_less(&c, &curve->order)) { // < order + scalar_multiply(curve, &c, child); // b = c * G + point_add(curve, parent, child); // b = a + b + if(!point_is_infinity(child)) { + if(child_chain_code) { + memcpy(child_chain_code, I + 32, 32); + } + + // Wipe all stack data. + memzero(data, sizeof(data)); + memzero(I, sizeof(I)); + memzero(&c, sizeof(c)); + return 1; + } + } + + data[0] = 1; + memcpy(data + 1, I + 32, 32); + } +} + +int hdnode_public_ckd(HDNode* inout, uint32_t i) { + curve_point parent = {0}, child = {0}; + + if(!ecdsa_read_pubkey(inout->curve->params, inout->public_key, &parent)) { + return 0; + } + if(!hdnode_public_ckd_cp( + inout->curve->params, &parent, inout->chain_code, i, &child, inout->chain_code)) { + return 0; + } + memzero(inout->private_key, 32); + inout->depth++; + inout->child_num = i; + inout->public_key[0] = 0x02 | (child.y.val[0] & 0x01); + bn_write_be(&child.x, inout->public_key + 1); + + // Wipe all stack data. + memzero(&parent, sizeof(parent)); + memzero(&child, sizeof(child)); + + return 1; +} + +void hdnode_public_ckd_address_optimized( + const curve_point* pub, + const uint8_t* chain_code, + uint32_t i, + uint32_t version, + HasherType hasher_pubkey, + HasherType hasher_base58, + char* addr, + int addrsize, + int addrformat) { + uint8_t child_pubkey[33] = {0}; + curve_point b = {0}; + + hdnode_public_ckd_cp(&secp256k1, pub, chain_code, i, &b, NULL); + child_pubkey[0] = 0x02 | (b.y.val[0] & 0x01); + bn_write_be(&b.x, child_pubkey + 1); + + switch(addrformat) { + case 1: // Segwit-in-P2SH + ecdsa_get_address_segwit_p2sh( + child_pubkey, version, hasher_pubkey, hasher_base58, addr, addrsize); + break; + default: // normal address + ecdsa_get_address(child_pubkey, version, hasher_pubkey, hasher_base58, addr, addrsize); + break; + } +} + +#if USE_BIP32_CACHE +static bool private_ckd_cache_root_set = false; +static CONFIDENTIAL HDNode private_ckd_cache_root; +static int private_ckd_cache_index = 0; + +static CONFIDENTIAL struct { + bool set; + size_t depth; + uint32_t i[BIP32_CACHE_MAXDEPTH]; + HDNode node; +} private_ckd_cache[BIP32_CACHE_SIZE]; + +void bip32_cache_clear(void) { + private_ckd_cache_root_set = false; + private_ckd_cache_index = 0; + memzero(&private_ckd_cache_root, sizeof(private_ckd_cache_root)); + memzero(private_ckd_cache, sizeof(private_ckd_cache)); +} + +int hdnode_private_ckd_cached( + HDNode* inout, + const uint32_t* i, + size_t i_count, + uint32_t* fingerprint) { + if(i_count == 0) { + // no way how to compute parent fingerprint + return 1; + } + if(i_count == 1) { + if(fingerprint) { + *fingerprint = hdnode_fingerprint(inout); + } + if(hdnode_private_ckd(inout, i[0]) == 0) return 0; + return 1; + } + + bool found = false; + // if root is not set or not the same + if(!private_ckd_cache_root_set || + memcmp(&private_ckd_cache_root, inout, sizeof(HDNode)) != 0) { + // clear the cache + private_ckd_cache_index = 0; + memzero(private_ckd_cache, sizeof(private_ckd_cache)); + // setup new root + memcpy(&private_ckd_cache_root, inout, sizeof(HDNode)); + private_ckd_cache_root_set = true; + } else { + // try to find parent + int j = 0; + for(j = 0; j < BIP32_CACHE_SIZE; j++) { + if(private_ckd_cache[j].set && private_ckd_cache[j].depth == i_count - 1 && + memcmp(private_ckd_cache[j].i, i, (i_count - 1) * sizeof(uint32_t)) == 0 && + private_ckd_cache[j].node.curve == inout->curve) { + memcpy(inout, &(private_ckd_cache[j].node), sizeof(HDNode)); + found = true; + break; + } + } + } + + // else derive parent + if(!found) { + size_t k = 0; + for(k = 0; k < i_count - 1; k++) { + if(hdnode_private_ckd(inout, i[k]) == 0) return 0; + } + // and save it + memzero( + &(private_ckd_cache[private_ckd_cache_index]), + sizeof(private_ckd_cache[private_ckd_cache_index])); + private_ckd_cache[private_ckd_cache_index].set = true; + private_ckd_cache[private_ckd_cache_index].depth = i_count - 1; + memcpy(private_ckd_cache[private_ckd_cache_index].i, i, (i_count - 1) * sizeof(uint32_t)); + memcpy(&(private_ckd_cache[private_ckd_cache_index].node), inout, sizeof(HDNode)); + private_ckd_cache_index = (private_ckd_cache_index + 1) % BIP32_CACHE_SIZE; + } + + if(fingerprint) { + *fingerprint = hdnode_fingerprint(inout); + } + if(hdnode_private_ckd(inout, i[i_count - 1]) == 0) return 0; + + return 1; +} +#endif + +int hdnode_get_address_raw(HDNode* node, uint32_t version, uint8_t* addr_raw) { + if(hdnode_fill_public_key(node) != 0) { + return 1; + } + ecdsa_get_address_raw(node->public_key, version, node->curve->hasher_pubkey, addr_raw); + return 0; +} + +int hdnode_get_address(HDNode* node, uint32_t version, char* addr, int addrsize) { + if(hdnode_fill_public_key(node) != 0) { + return 1; + } + ecdsa_get_address( + node->public_key, + version, + node->curve->hasher_pubkey, + node->curve->hasher_base58, + addr, + addrsize); + return 0; +} + +int hdnode_fill_public_key(HDNode* node) { + if(node->public_key[0] != 0) return 0; + +#if USE_BIP32_25519_CURVES + if(node->curve->params) { + if(ecdsa_get_public_key33(node->curve->params, node->private_key, node->public_key) != 0) { + return 1; + } + } else { + node->public_key[0] = 1; + if(node->curve == &ed25519_info) { + ed25519_publickey(node->private_key, node->public_key + 1); + } else if(node->curve == &ed25519_sha3_info) { + ed25519_publickey_sha3(node->private_key, node->public_key + 1); +#if USE_KECCAK + } else if(node->curve == &ed25519_keccak_info) { + ed25519_publickey_keccak(node->private_key, node->public_key + 1); +#endif + } else if(node->curve == &curve25519_info) { + curve25519_scalarmult_basepoint(node->public_key + 1, node->private_key); +#if USE_CARDANO + } else if(node->curve == &ed25519_cardano_info) { + ed25519_publickey_ext(node->private_key, node->public_key + 1); +#endif + } + } +#else + + if(ecdsa_get_public_key33(node->curve->params, node->private_key, node->public_key) != 0) { + return 1; + } +#endif + return 0; +} + +#if USE_ETHEREUM +int hdnode_get_ethereum_pubkeyhash(const HDNode* node, uint8_t* pubkeyhash) { + uint8_t buf[65] = {0}; + //SHA3_CTX ctx = {0}; + SHA3_CTX* ctx = malloc(sizeof(SHA3_CTX)); + memzero(ctx, sizeof(SHA3_CTX)); + + /* get uncompressed public key */ + if(ecdsa_get_public_key65(node->curve->params, node->private_key, buf) != 0) { + memzero(ctx, sizeof(SHA3_CTX)); + free(ctx); + return 0; + } + + /* compute sha3 of x and y coordinate without 04 prefix */ + sha3_256_Init(ctx); + sha3_Update(ctx, buf + 1, 64); + keccak_Final(ctx, buf); + + memzero(ctx, sizeof(SHA3_CTX)); + free(ctx); + + /* result are the least significant 160 bits */ + memcpy(pubkeyhash, buf + 12, 20); + + return 1; +} +#endif + +#if USE_NEM +int hdnode_get_nem_address(HDNode* node, uint8_t version, char* address) { + if(node->curve != &ed25519_keccak_info) { + return 0; + } + + if(hdnode_fill_public_key(node) != 0) { + return 0; + } + + return nem_get_address(&node->public_key[1], version, address); +} + +int hdnode_get_nem_shared_key( + const HDNode* node, + const ed25519_public_key peer_public_key, + const uint8_t* salt, + ed25519_public_key mul, + uint8_t* shared_key) { + if(node->curve != &ed25519_keccak_info) { + return 0; + } + + // sizeof(ed25519_public_key) == SHA3_256_DIGEST_LENGTH + if(mul == NULL) mul = shared_key; + + if(ed25519_scalarmult_keccak(mul, node->private_key, peer_public_key)) { + return 0; + } + + for(size_t i = 0; i < 32; i++) { + shared_key[i] = mul[i] ^ salt[i]; + } + + keccak_256(shared_key, 32, shared_key); + return 1; +} + +int hdnode_nem_encrypt( + const HDNode* node, + const ed25519_public_key public_key, + const uint8_t* iv_immut, + const uint8_t* salt, + const uint8_t* payload, + size_t size, + uint8_t* buffer) { + uint8_t last_block[AES_BLOCK_SIZE] = {0}; + uint8_t remainder = size % AES_BLOCK_SIZE; + + // Round down to last whole block + size -= remainder; + // Copy old last block + memcpy(last_block, &payload[size], remainder); + // Pad new last block with number of missing bytes + memset(&last_block[remainder], AES_BLOCK_SIZE - remainder, AES_BLOCK_SIZE - remainder); + + // the IV gets mutated, so we make a copy not to touch the original + uint8_t iv[AES_BLOCK_SIZE] = {0}; + memcpy(iv, iv_immut, AES_BLOCK_SIZE); + + uint8_t shared_key[SHA3_256_DIGEST_LENGTH] = {0}; + if(!hdnode_get_nem_shared_key(node, public_key, salt, NULL, shared_key)) { + return 0; + } + + aes_encrypt_ctx ctx = {0}; + + int ret = aes_encrypt_key256(shared_key, &ctx); + memzero(shared_key, sizeof(shared_key)); + + if(ret != EXIT_SUCCESS) { + return 0; + } + + if(aes_cbc_encrypt(payload, buffer, size, iv, &ctx) != EXIT_SUCCESS) { + return 0; + } + + if(aes_cbc_encrypt(last_block, &buffer[size], sizeof(last_block), iv, &ctx) != EXIT_SUCCESS) { + return 0; + } + + return 1; +} + +int hdnode_nem_decrypt( + const HDNode* node, + const ed25519_public_key public_key, + uint8_t* iv, + const uint8_t* salt, + const uint8_t* payload, + size_t size, + uint8_t* buffer) { + uint8_t shared_key[SHA3_256_DIGEST_LENGTH] = {0}; + + if(!hdnode_get_nem_shared_key(node, public_key, salt, NULL, shared_key)) { + return 0; + } + + aes_decrypt_ctx ctx = {0}; + + int ret = aes_decrypt_key256(shared_key, &ctx); + memzero(shared_key, sizeof(shared_key)); + + if(ret != EXIT_SUCCESS) { + return 0; + } + + if(aes_cbc_decrypt(payload, buffer, size, iv, &ctx) != EXIT_SUCCESS) { + return 0; + } + + return 1; +} +#endif + +// msg is a data to be signed +// msg_len is the message length +int hdnode_sign( + HDNode* node, + const uint8_t* msg, + uint32_t msg_len, + HasherType hasher_sign, + uint8_t* sig, + uint8_t* pby, + int (*is_canonical)(uint8_t by, uint8_t sig[64])) { + if(node->curve->params) { + return ecdsa_sign( + node->curve->params, + hasher_sign, + node->private_key, + msg, + msg_len, + sig, + pby, + is_canonical); + } else if(node->curve == &curve25519_info) { + return 1; // signatures are not supported + } else { + if(node->curve == &ed25519_info) { + ed25519_sign(msg, msg_len, node->private_key, sig); + } else if(node->curve == &ed25519_sha3_info) { + ed25519_sign_sha3(msg, msg_len, node->private_key, sig); +#if USE_KECCAK + } else if(node->curve == &ed25519_keccak_info) { + ed25519_sign_keccak(msg, msg_len, node->private_key, sig); +#endif + } else { + return 1; // unknown or unsupported curve + } + return 0; + } +} + +int hdnode_sign_digest( + HDNode* node, + const uint8_t* digest, + uint8_t* sig, + uint8_t* pby, + int (*is_canonical)(uint8_t by, uint8_t sig[64])) { + if(node->curve->params) { + return ecdsa_sign_digest( + node->curve->params, node->private_key, digest, sig, pby, is_canonical); + } else if(node->curve == &curve25519_info) { + return 1; // signatures are not supported + } else { + return hdnode_sign(node, digest, 32, 0, sig, pby, is_canonical); + } +} + +int hdnode_get_shared_key( + const HDNode* node, + const uint8_t* peer_public_key, + uint8_t* session_key, + int* result_size) { + // Use elliptic curve Diffie-Helman to compute shared session key + if(node->curve->params) { + if(ecdh_multiply(node->curve->params, node->private_key, peer_public_key, session_key) != + 0) { + return 1; + } + *result_size = 65; + return 0; + } else if(node->curve == &curve25519_info) { + session_key[0] = 0x04; + if(peer_public_key[0] != 0x40) { + return 1; // Curve25519 public key should start with 0x40 byte. + } + curve25519_scalarmult(session_key + 1, node->private_key, peer_public_key + 1); + *result_size = 33; + return 0; + } else { + *result_size = 0; + return 1; // ECDH is not supported + } +} + +static int hdnode_serialize( + const HDNode* node, + uint32_t fingerprint, + uint32_t version, + bool use_private, + char* str, + int strsize) { + uint8_t node_data[78] = {0}; + write_be(node_data, version); + node_data[4] = node->depth; + write_be(node_data + 5, fingerprint); + write_be(node_data + 9, node->child_num); + memcpy(node_data + 13, node->chain_code, 32); + if(use_private) { + node_data[45] = 0; + memcpy(node_data + 46, node->private_key, 32); + } else { + memcpy(node_data + 45, node->public_key, 33); + } + int ret = base58_encode_check( + node_data, sizeof(node_data), node->curve->hasher_base58, str, strsize); + memzero(node_data, sizeof(node_data)); + return ret; +} + +int hdnode_serialize_public( + const HDNode* node, + uint32_t fingerprint, + uint32_t version, + char* str, + int strsize) { + return hdnode_serialize(node, fingerprint, version, false, str, strsize); +} + +int hdnode_serialize_private( + const HDNode* node, + uint32_t fingerprint, + uint32_t version, + char* str, + int strsize) { + return hdnode_serialize(node, fingerprint, version, true, str, strsize); +} + +// check for validity of curve point in case of public data not performed +static int hdnode_deserialize( + const char* str, + uint32_t version, + bool use_private, + const char* curve, + HDNode* node, + uint32_t* fingerprint) { + uint8_t node_data[78] = {0}; + memzero(node, sizeof(HDNode)); + node->curve = get_curve_by_name(curve); + if(base58_decode_check(str, node->curve->hasher_base58, node_data, sizeof(node_data)) != + sizeof(node_data)) { + return -1; + } + uint32_t ver = read_be(node_data); + if(ver != version) { + return -3; // invalid version + } + if(use_private) { + // invalid data + if(node_data[45]) { + return -2; + } + memcpy(node->private_key, node_data + 46, 32); + memzero(node->public_key, sizeof(node->public_key)); + } else { + memzero(node->private_key, sizeof(node->private_key)); + memcpy(node->public_key, node_data + 45, 33); + } + node->depth = node_data[4]; + if(fingerprint) { + *fingerprint = read_be(node_data + 5); + } + node->child_num = read_be(node_data + 9); + memcpy(node->chain_code, node_data + 13, 32); + return 0; +} + +int hdnode_deserialize_public( + const char* str, + uint32_t version, + const char* curve, + HDNode* node, + uint32_t* fingerprint) { + return hdnode_deserialize(str, version, false, curve, node, fingerprint); +} + +int hdnode_deserialize_private( + const char* str, + uint32_t version, + const char* curve, + HDNode* node, + uint32_t* fingerprint) { + return hdnode_deserialize(str, version, true, curve, node, fingerprint); +} + +const curve_info* get_curve_by_name(const char* curve_name) { + if(curve_name == 0) { + return 0; + } + if(strcmp(curve_name, SECP256K1_NAME) == 0) { + return &secp256k1_info; + } + if(strcmp(curve_name, SECP256K1_DECRED_NAME) == 0) { + return &secp256k1_decred_info; + } + if(strcmp(curve_name, SECP256K1_GROESTL_NAME) == 0) { + return &secp256k1_groestl_info; + } + if(strcmp(curve_name, SECP256K1_SMART_NAME) == 0) { + return &secp256k1_smart_info; + } + if(strcmp(curve_name, NIST256P1_NAME) == 0) { + return &nist256p1_info; + } + if(strcmp(curve_name, ED25519_NAME) == 0) { + return &ed25519_info; + } +#if USE_CARDANO + if(strcmp(curve_name, ED25519_CARDANO_NAME) == 0) { + return &ed25519_cardano_info; + } +#endif + if(strcmp(curve_name, ED25519_SHA3_NAME) == 0) { + return &ed25519_sha3_info; + } +#if USE_KECCAK + if(strcmp(curve_name, ED25519_KECCAK_NAME) == 0) { + return &ed25519_keccak_info; + } +#endif + if(strcmp(curve_name, CURVE25519_NAME) == 0) { + return &curve25519_info; + } + return 0; +} diff --git a/applications/external/flipbip/lib/crypto/bip32.h b/applications/external/flipbip/lib/crypto/bip32.h new file mode 100644 index 000000000..3e3114848 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/bip32.h @@ -0,0 +1,202 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BIP32_H__ +#define __BIP32_H__ + +#include +#include +#include +#include "ecdsa.h" +#include "ed25519_donna/ed25519.h" +#include "options.h" + +// Maximum length of a Base58Check-encoded extended public or private key. +#define XPUB_MAXLEN 112 + +// Maximum length of a Base58Check-encoded address. +#define ADDRESS_MAXLEN 39 + +typedef struct { + const char* bip32_name; // string for generating BIP32 xprv from seed + const ecdsa_curve* params; // ecdsa curve parameters, null for ed25519 + + HasherType hasher_base58; + HasherType hasher_sign; + HasherType hasher_pubkey; + HasherType hasher_script; +} curve_info; + +typedef struct { + uint32_t depth; + uint32_t child_num; + uint8_t chain_code[32]; + + uint8_t private_key[32]; + uint8_t private_key_extension[32]; + + uint8_t public_key[33]; + const curve_info* curve; +} HDNode; + +int hdnode_from_xpub( + uint32_t depth, + uint32_t child_num, + const uint8_t* chain_code, + const uint8_t* public_key, + const char* curve, + HDNode* out); + +int hdnode_from_xprv( + uint32_t depth, + uint32_t child_num, + const uint8_t* chain_code, + const uint8_t* private_key, + const char* curve, + HDNode* out); + +int hdnode_from_seed(const uint8_t* seed, int seed_len, const char* curve, HDNode* out); + +#define hdnode_private_ckd_prime(X, I) hdnode_private_ckd((X), ((I) | 0x80000000)) + +int hdnode_private_ckd(HDNode* inout, uint32_t i); + +int hdnode_public_ckd_cp( + const ecdsa_curve* curve, + const curve_point* parent, + const uint8_t* parent_chain_code, + uint32_t i, + curve_point* child, + uint8_t* child_chain_code); + +int hdnode_public_ckd(HDNode* inout, uint32_t i); + +void hdnode_public_ckd_address_optimized( + const curve_point* pub, + const uint8_t* chain_code, + uint32_t i, + uint32_t version, + HasherType hasher_pubkey, + HasherType hasher_base58, + char* addr, + int addrsize, + int addrformat); + +#if USE_BIP32_CACHE +void bip32_cache_clear(void); +int hdnode_private_ckd_cached( + HDNode* inout, + const uint32_t* i, + size_t i_count, + uint32_t* fingerprint); +#endif + +uint32_t hdnode_fingerprint(HDNode* node); + +int hdnode_fill_public_key(HDNode* node); + +#if USE_ETHEREUM +int hdnode_get_ethereum_pubkeyhash(const HDNode* node, uint8_t* pubkeyhash); +#endif + +#if USE_NEM +int hdnode_get_nem_address(HDNode* node, uint8_t version, char* address); +int hdnode_get_nem_shared_key( + const HDNode* node, + const ed25519_public_key peer_public_key, + const uint8_t* salt, + ed25519_public_key mul, + uint8_t* shared_key); +int hdnode_nem_encrypt( + const HDNode* node, + const ed25519_public_key public_key, + const uint8_t* iv, + const uint8_t* salt, + const uint8_t* payload, + size_t size, + uint8_t* buffer); +int hdnode_nem_decrypt( + const HDNode* node, + const ed25519_public_key public_key, + uint8_t* iv, + const uint8_t* salt, + const uint8_t* payload, + size_t size, + uint8_t* buffer); +#endif + +int hdnode_sign( + HDNode* node, + const uint8_t* msg, + uint32_t msg_len, + HasherType hasher_sign, + uint8_t* sig, + uint8_t* pby, + int (*is_canonical)(uint8_t by, uint8_t sig[64])); +int hdnode_sign_digest( + HDNode* node, + const uint8_t* digest, + uint8_t* sig, + uint8_t* pby, + int (*is_canonical)(uint8_t by, uint8_t sig[64])); + +int hdnode_get_shared_key( + const HDNode* node, + const uint8_t* peer_public_key, + uint8_t* session_key, + int* result_size); + +int hdnode_serialize_public( + const HDNode* node, + uint32_t fingerprint, + uint32_t version, + char* str, + int strsize); + +int hdnode_serialize_private( + const HDNode* node, + uint32_t fingerprint, + uint32_t version, + char* str, + int strsize); + +int hdnode_deserialize_public( + const char* str, + uint32_t version, + const char* curve, + HDNode* node, + uint32_t* fingerprint); + +int hdnode_deserialize_private( + const char* str, + uint32_t version, + const char* curve, + HDNode* node, + uint32_t* fingerprint); + +int hdnode_get_address_raw(HDNode* node, uint32_t version, uint8_t* addr_raw); +int hdnode_get_address(HDNode* node, uint32_t version, char* addr, int addrsize); + +const curve_info* get_curve_by_name(const char* curve_name); + +#endif diff --git a/applications/external/flipbip/lib/crypto/bip39.c b/applications/external/flipbip/lib/crypto/bip39.c new file mode 100644 index 000000000..c99fe76c9 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/bip39.c @@ -0,0 +1,288 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include + +#include "bip39.h" +#include "hmac.h" +#include "memzero.h" +#include "options.h" +#include "pbkdf2.h" +#include "rand.h" +#include "sha2.h" + +#if USE_BIP39_CACHE + +static int bip39_cache_index = 0; + +static CONFIDENTIAL struct { + bool set; + char mnemonic[256]; + char passphrase[64]; + uint8_t seed[512 / 8]; +} bip39_cache[BIP39_CACHE_SIZE]; + +void bip39_cache_clear(void) { + memzero(bip39_cache, sizeof(bip39_cache)); + bip39_cache_index = 0; +} + +#endif + +const char* mnemonic_generate(int strength) { + if(strength % 32 || strength < 128 || strength > 256) { + return 0; + } + uint8_t data[32] = {0}; + random_buffer(data, 32); + const char* r = mnemonic_from_data(data, strength / 8); + memzero(data, sizeof(data)); + return r; +} + +static CONFIDENTIAL char mnemo[24 * 10]; + +const char* mnemonic_from_data(const uint8_t* data, int len) { + if(len % 4 || len < 16 || len > 32) { + return 0; + } + + uint8_t bits[32 + 1] = {0}; + + sha256_Raw(data, len, bits); + // checksum + bits[len] = bits[0]; + // data + memcpy(bits, data, len); + + int mlen = len * 3 / 4; + + int i = 0, j = 0, idx = 0; + char* p = mnemo; + for(i = 0; i < mlen; i++) { + idx = 0; + for(j = 0; j < 11; j++) { + idx <<= 1; + idx += (bits[(i * 11 + j) / 8] & (1 << (7 - ((i * 11 + j) % 8)))) > 0; + } + strcpy(p, BIP39_WORDLIST_ENGLISH[idx]); + p += strlen(BIP39_WORDLIST_ENGLISH[idx]); + *p = (i < mlen - 1) ? ' ' : 0; + p++; + } + memzero(bits, sizeof(bits)); + + return mnemo; +} + +void mnemonic_clear(void) { + memzero(mnemo, sizeof(mnemo)); +} + +int mnemonic_to_bits(const char* mnemonic, uint8_t* bits) { + if(!mnemonic) { + return 0; + } + + uint32_t i = 0, n = 0; + + while(mnemonic[i]) { + if(mnemonic[i] == ' ') { + n++; + } + i++; + } + n++; + + // check that number of words is valid for BIP-39: + // (a) between 128 and 256 bits of initial entropy (12 - 24 words) + // (b) number of bits divisible by 33 (1 checksum bit per 32 input bits) + // - that is, (n * 11) % 33 == 0, so n % 3 == 0 + if(n < 12 || n > 24 || (n % 3)) { + return 0; + } + + char current_word[10] = {0}; + uint32_t j = 0, ki = 0, bi = 0; + uint8_t result[32 + 1] = {0}; + + memzero(result, sizeof(result)); + i = 0; + while(mnemonic[i]) { + j = 0; + while(mnemonic[i] != ' ' && mnemonic[i] != 0) { + if(j >= sizeof(current_word) - 1) { + return 0; + } + current_word[j] = mnemonic[i]; + i++; + j++; + } + current_word[j] = 0; + if(mnemonic[i] != 0) { + i++; + } + int k = mnemonic_find_word(current_word); + if(k < 0) { // word not found + return 0; + } + for(ki = 0; ki < 11; ki++) { + if(k & (1 << (10 - ki))) { + result[bi / 8] |= 1 << (7 - (bi % 8)); + } + bi++; + } + } + if(bi != n * 11) { + return 0; + } + memcpy(bits, result, sizeof(result)); + memzero(result, sizeof(result)); + + // returns amount of entropy + checksum BITS + return n * 11; +} + +int mnemonic_check(const char* mnemonic) { + uint8_t bits[32 + 1] = {0}; + int mnemonic_bits_len = mnemonic_to_bits(mnemonic, bits); + if(mnemonic_bits_len != (12 * 11) && mnemonic_bits_len != (18 * 11) && + mnemonic_bits_len != (24 * 11)) { + return 0; + } + int words = mnemonic_bits_len / 11; + + uint8_t checksum = bits[words * 4 / 3]; + sha256_Raw(bits, words * 4 / 3, bits); + if(words == 12) { + return (bits[0] & 0xF0) == (checksum & 0xF0); // compare first 4 bits + } else if(words == 18) { + return (bits[0] & 0xFC) == (checksum & 0xFC); // compare first 6 bits + } else if(words == 24) { + return bits[0] == checksum; // compare 8 bits + } + return 0; +} + +// passphrase must be at most 256 characters otherwise it would be truncated +void mnemonic_to_seed( + const char* mnemonic, + const char* passphrase, + uint8_t seed[512 / 8], + void (*progress_callback)(uint32_t current, uint32_t total)) { + int mnemoniclen = strlen(mnemonic); + int passphraselen = strlen(passphrase); + if(passphraselen > 256) passphraselen = 256; +#if USE_BIP39_CACHE + // check cache + if(mnemoniclen < 256 && passphraselen < 64) { + for(int i = 0; i < BIP39_CACHE_SIZE; i++) { + if(!bip39_cache[i].set) continue; + if(strcmp(bip39_cache[i].mnemonic, mnemonic) != 0) continue; + if(strcmp(bip39_cache[i].passphrase, passphrase) != 0) continue; + // found the correct entry + memcpy(seed, bip39_cache[i].seed, 512 / 8); + return; + } + } +#endif + uint8_t salt[8 + 256] = {0}; + memcpy(salt, "mnemonic", 8); + memcpy(salt + 8, passphrase, passphraselen); + static CONFIDENTIAL PBKDF2_HMAC_SHA512_CTX pctx; + pbkdf2_hmac_sha512_Init( + &pctx, (const uint8_t*)mnemonic, mnemoniclen, salt, passphraselen + 8, 1); + if(progress_callback) { + progress_callback(0, BIP39_PBKDF2_ROUNDS); + } + for(int i = 0; i < 16; i++) { + pbkdf2_hmac_sha512_Update(&pctx, BIP39_PBKDF2_ROUNDS / 16); + if(progress_callback) { + progress_callback((i + 1) * BIP39_PBKDF2_ROUNDS / 16, BIP39_PBKDF2_ROUNDS); + } + } + pbkdf2_hmac_sha512_Final(&pctx, seed); + memzero(salt, sizeof(salt)); +#if USE_BIP39_CACHE + // store to cache + if(mnemoniclen < 256 && passphraselen < 64) { + bip39_cache[bip39_cache_index].set = true; + strcpy(bip39_cache[bip39_cache_index].mnemonic, mnemonic); + strcpy(bip39_cache[bip39_cache_index].passphrase, passphrase); + memcpy(bip39_cache[bip39_cache_index].seed, seed, 512 / 8); + bip39_cache_index = (bip39_cache_index + 1) % BIP39_CACHE_SIZE; + } +#endif +} + +// binary search for finding the word in the wordlist +int mnemonic_find_word(const char* word) { + int lo = 0, hi = BIP39_WORD_COUNT - 1; + while(lo <= hi) { + int mid = lo + (hi - lo) / 2; + int cmp = strcmp(word, BIP39_WORDLIST_ENGLISH[mid]); + if(cmp == 0) { + return mid; + } + if(cmp > 0) { + lo = mid + 1; + } else { + hi = mid - 1; + } + } + return -1; +} + +const char* mnemonic_complete_word(const char* prefix, int len) { + // we need to perform linear search, + // because we want to return the first match + for(int i = 0; i < BIP39_WORD_COUNT; i++) { + if(strncmp(BIP39_WORDLIST_ENGLISH[i], prefix, len) == 0) { + return BIP39_WORDLIST_ENGLISH[i]; + } + } + return NULL; +} + +const char* mnemonic_get_word(int index) { + if(index >= 0 && index < BIP39_WORD_COUNT) { + return BIP39_WORDLIST_ENGLISH[index]; + } else { + return NULL; + } +} + +uint32_t mnemonic_word_completion_mask(const char* prefix, int len) { + if(len <= 0) { + return 0x3ffffff; // all letters (bits 1-26 set) + } + uint32_t res = 0; + for(int i = 0; i < BIP39_WORD_COUNT; i++) { + const char* word = BIP39_WORDLIST_ENGLISH[i]; + if(strncmp(word, prefix, len) == 0 && word[len] >= 'a' && word[len] <= 'z') { + res |= 1 << (word[len] - 'a'); + } + } + return res; +} diff --git a/applications/external/flipbip/lib/crypto/bip39.h b/applications/external/flipbip/lib/crypto/bip39.h new file mode 100644 index 000000000..5e29c8336 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/bip39.h @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BIP39_H__ +#define __BIP39_H__ + +#include +#include + +#include "options.h" + +#define BIP39_WORD_COUNT 2048 +#define BIP39_PBKDF2_ROUNDS 2048 + +#if USE_BIP39_CACHE +void bip39_cache_clear(void); +#endif + +extern const char* const BIP39_WORDLIST_ENGLISH[BIP39_WORD_COUNT]; + +const char* mnemonic_generate(int strength); // strength in bits +const char* mnemonic_from_data(const uint8_t* data, int len); +void mnemonic_clear(void); + +int mnemonic_check(const char* mnemonic); + +int mnemonic_to_bits(const char* mnemonic, uint8_t* bits); + +// passphrase must be at most 256 characters otherwise it would be truncated +void mnemonic_to_seed( + const char* mnemonic, + const char* passphrase, + uint8_t seed[512 / 8], + void (*progress_callback)(uint32_t current, uint32_t total)); + +int mnemonic_find_word(const char* word); +const char* mnemonic_complete_word(const char* prefix, int len); +const char* mnemonic_get_word(int index); +uint32_t mnemonic_word_completion_mask(const char* prefix, int len); + +#endif diff --git a/applications/external/flipbip/lib/crypto/bip39_english.c b/applications/external/flipbip/lib/crypto/bip39_english.c new file mode 100644 index 000000000..4b92b4c7f --- /dev/null +++ b/applications/external/flipbip/lib/crypto/bip39_english.c @@ -0,0 +1,283 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "bip39.h" + +const char* const BIP39_WORDLIST_ENGLISH[BIP39_WORD_COUNT] = { + "abandon", "ability", "able", "about", "above", "absent", "absorb", "abstract", + "absurd", "abuse", "access", "accident", "account", "accuse", "achieve", "acid", + "acoustic", "acquire", "across", "act", "action", "actor", "actress", "actual", + "adapt", "add", "addict", "address", "adjust", "admit", "adult", "advance", + "advice", "aerobic", "affair", "afford", "afraid", "again", "age", "agent", + "agree", "ahead", "aim", "air", "airport", "aisle", "alarm", "album", + "alcohol", "alert", "alien", "all", "alley", "allow", "almost", "alone", + "alpha", "already", "also", "alter", "always", "amateur", "amazing", "among", + "amount", "amused", "analyst", "anchor", "ancient", "anger", "angle", "angry", + "animal", "ankle", "announce", "annual", "another", "answer", "antenna", "antique", + "anxiety", "any", "apart", "apology", "appear", "apple", "approve", "april", + "arch", "arctic", "area", "arena", "argue", "arm", "armed", "armor", + "army", "around", "arrange", "arrest", "arrive", "arrow", "art", "artefact", + "artist", "artwork", "ask", "aspect", "assault", "asset", "assist", "assume", + "asthma", "athlete", "atom", "attack", "attend", "attitude", "attract", "auction", + "audit", "august", "aunt", "author", "auto", "autumn", "average", "avocado", + "avoid", "awake", "aware", "away", "awesome", "awful", "awkward", "axis", + "baby", "bachelor", "bacon", "badge", "bag", "balance", "balcony", "ball", + "bamboo", "banana", "banner", "bar", "barely", "bargain", "barrel", "base", + "basic", "basket", "battle", "beach", "bean", "beauty", "because", "become", + "beef", "before", "begin", "behave", "behind", "believe", "below", "belt", + "bench", "benefit", "best", "betray", "better", "between", "beyond", "bicycle", + "bid", "bike", "bind", "biology", "bird", "birth", "bitter", "black", + "blade", "blame", "blanket", "blast", "bleak", "bless", "blind", "blood", + "blossom", "blouse", "blue", "blur", "blush", "board", "boat", "body", + "boil", "bomb", "bone", "bonus", "book", "boost", "border", "boring", + "borrow", "boss", "bottom", "bounce", "box", "boy", "bracket", "brain", + "brand", "brass", "brave", "bread", "breeze", "brick", "bridge", "brief", + "bright", "bring", "brisk", "broccoli", "broken", "bronze", "broom", "brother", + "brown", "brush", "bubble", "buddy", "budget", "buffalo", "build", "bulb", + "bulk", "bullet", "bundle", "bunker", "burden", "burger", "burst", "bus", + "business", "busy", "butter", "buyer", "buzz", "cabbage", "cabin", "cable", + "cactus", "cage", "cake", "call", "calm", "camera", "camp", "can", + "canal", "cancel", "candy", "cannon", "canoe", "canvas", "canyon", "capable", + "capital", "captain", "car", "carbon", "card", "cargo", "carpet", "carry", + "cart", "case", "cash", "casino", "castle", "casual", "cat", "catalog", + "catch", "category", "cattle", "caught", "cause", "caution", "cave", "ceiling", + "celery", "cement", "census", "century", "cereal", "certain", "chair", "chalk", + "champion", "change", "chaos", "chapter", "charge", "chase", "chat", "cheap", + "check", "cheese", "chef", "cherry", "chest", "chicken", "chief", "child", + "chimney", "choice", "choose", "chronic", "chuckle", "chunk", "churn", "cigar", + "cinnamon", "circle", "citizen", "city", "civil", "claim", "clap", "clarify", + "claw", "clay", "clean", "clerk", "clever", "click", "client", "cliff", + "climb", "clinic", "clip", "clock", "clog", "close", "cloth", "cloud", + "clown", "club", "clump", "cluster", "clutch", "coach", "coast", "coconut", + "code", "coffee", "coil", "coin", "collect", "color", "column", "combine", + "come", "comfort", "comic", "common", "company", "concert", "conduct", "confirm", + "congress", "connect", "consider", "control", "convince", "cook", "cool", "copper", + "copy", "coral", "core", "corn", "correct", "cost", "cotton", "couch", + "country", "couple", "course", "cousin", "cover", "coyote", "crack", "cradle", + "craft", "cram", "crane", "crash", "crater", "crawl", "crazy", "cream", + "credit", "creek", "crew", "cricket", "crime", "crisp", "critic", "crop", + "cross", "crouch", "crowd", "crucial", "cruel", "cruise", "crumble", "crunch", + "crush", "cry", "crystal", "cube", "culture", "cup", "cupboard", "curious", + "current", "curtain", "curve", "cushion", "custom", "cute", "cycle", "dad", + "damage", "damp", "dance", "danger", "daring", "dash", "daughter", "dawn", + "day", "deal", "debate", "debris", "decade", "december", "decide", "decline", + "decorate", "decrease", "deer", "defense", "define", "defy", "degree", "delay", + "deliver", "demand", "demise", "denial", "dentist", "deny", "depart", "depend", + "deposit", "depth", "deputy", "derive", "describe", "desert", "design", "desk", + "despair", "destroy", "detail", "detect", "develop", "device", "devote", "diagram", + "dial", "diamond", "diary", "dice", "diesel", "diet", "differ", "digital", + "dignity", "dilemma", "dinner", "dinosaur", "direct", "dirt", "disagree", "discover", + "disease", "dish", "dismiss", "disorder", "display", "distance", "divert", "divide", + "divorce", "dizzy", "doctor", "document", "dog", "doll", "dolphin", "domain", + "donate", "donkey", "donor", "door", "dose", "double", "dove", "draft", + "dragon", "drama", "drastic", "draw", "dream", "dress", "drift", "drill", + "drink", "drip", "drive", "drop", "drum", "dry", "duck", "dumb", + "dune", "during", "dust", "dutch", "duty", "dwarf", "dynamic", "eager", + "eagle", "early", "earn", "earth", "easily", "east", "easy", "echo", + "ecology", "economy", "edge", "edit", "educate", "effort", "egg", "eight", + "either", "elbow", "elder", "electric", "elegant", "element", "elephant", "elevator", + "elite", "else", "embark", "embody", "embrace", "emerge", "emotion", "employ", + "empower", "empty", "enable", "enact", "end", "endless", "endorse", "enemy", + "energy", "enforce", "engage", "engine", "enhance", "enjoy", "enlist", "enough", + "enrich", "enroll", "ensure", "enter", "entire", "entry", "envelope", "episode", + "equal", "equip", "era", "erase", "erode", "erosion", "error", "erupt", + "escape", "essay", "essence", "estate", "eternal", "ethics", "evidence", "evil", + "evoke", "evolve", "exact", "example", "excess", "exchange", "excite", "exclude", + "excuse", "execute", "exercise", "exhaust", "exhibit", "exile", "exist", "exit", + "exotic", "expand", "expect", "expire", "explain", "expose", "express", "extend", + "extra", "eye", "eyebrow", "fabric", "face", "faculty", "fade", "faint", + "faith", "fall", "false", "fame", "family", "famous", "fan", "fancy", + "fantasy", "farm", "fashion", "fat", "fatal", "father", "fatigue", "fault", + "favorite", "feature", "february", "federal", "fee", "feed", "feel", "female", + "fence", "festival", "fetch", "fever", "few", "fiber", "fiction", "field", + "figure", "file", "film", "filter", "final", "find", "fine", "finger", + "finish", "fire", "firm", "first", "fiscal", "fish", "fit", "fitness", + "fix", "flag", "flame", "flash", "flat", "flavor", "flee", "flight", + "flip", "float", "flock", "floor", "flower", "fluid", "flush", "fly", + "foam", "focus", "fog", "foil", "fold", "follow", "food", "foot", + "force", "forest", "forget", "fork", "fortune", "forum", "forward", "fossil", + "foster", "found", "fox", "fragile", "frame", "frequent", "fresh", "friend", + "fringe", "frog", "front", "frost", "frown", "frozen", "fruit", "fuel", + "fun", "funny", "furnace", "fury", "future", "gadget", "gain", "galaxy", + "gallery", "game", "gap", "garage", "garbage", "garden", "garlic", "garment", + "gas", "gasp", "gate", "gather", "gauge", "gaze", "general", "genius", + "genre", "gentle", "genuine", "gesture", "ghost", "giant", "gift", "giggle", + "ginger", "giraffe", "girl", "give", "glad", "glance", "glare", "glass", + "glide", "glimpse", "globe", "gloom", "glory", "glove", "glow", "glue", + "goat", "goddess", "gold", "good", "goose", "gorilla", "gospel", "gossip", + "govern", "gown", "grab", "grace", "grain", "grant", "grape", "grass", + "gravity", "great", "green", "grid", "grief", "grit", "grocery", "group", + "grow", "grunt", "guard", "guess", "guide", "guilt", "guitar", "gun", + "gym", "habit", "hair", "half", "hammer", "hamster", "hand", "happy", + "harbor", "hard", "harsh", "harvest", "hat", "have", "hawk", "hazard", + "head", "health", "heart", "heavy", "hedgehog", "height", "hello", "helmet", + "help", "hen", "hero", "hidden", "high", "hill", "hint", "hip", + "hire", "history", "hobby", "hockey", "hold", "hole", "holiday", "hollow", + "home", "honey", "hood", "hope", "horn", "horror", "horse", "hospital", + "host", "hotel", "hour", "hover", "hub", "huge", "human", "humble", + "humor", "hundred", "hungry", "hunt", "hurdle", "hurry", "hurt", "husband", + "hybrid", "ice", "icon", "idea", "identify", "idle", "ignore", "ill", + "illegal", "illness", "image", "imitate", "immense", "immune", "impact", "impose", + "improve", "impulse", "inch", "include", "income", "increase", "index", "indicate", + "indoor", "industry", "infant", "inflict", "inform", "inhale", "inherit", "initial", + "inject", "injury", "inmate", "inner", "innocent", "input", "inquiry", "insane", + "insect", "inside", "inspire", "install", "intact", "interest", "into", "invest", + "invite", "involve", "iron", "island", "isolate", "issue", "item", "ivory", + "jacket", "jaguar", "jar", "jazz", "jealous", "jeans", "jelly", "jewel", + "job", "join", "joke", "journey", "joy", "judge", "juice", "jump", + "jungle", "junior", "junk", "just", "kangaroo", "keen", "keep", "ketchup", + "key", "kick", "kid", "kidney", "kind", "kingdom", "kiss", "kit", + "kitchen", "kite", "kitten", "kiwi", "knee", "knife", "knock", "know", + "lab", "label", "labor", "ladder", "lady", "lake", "lamp", "language", + "laptop", "large", "later", "latin", "laugh", "laundry", "lava", "law", + "lawn", "lawsuit", "layer", "lazy", "leader", "leaf", "learn", "leave", + "lecture", "left", "leg", "legal", "legend", "leisure", "lemon", "lend", + "length", "lens", "leopard", "lesson", "letter", "level", "liar", "liberty", + "library", "license", "life", "lift", "light", "like", "limb", "limit", + "link", "lion", "liquid", "list", "little", "live", "lizard", "load", + "loan", "lobster", "local", "lock", "logic", "lonely", "long", "loop", + "lottery", "loud", "lounge", "love", "loyal", "lucky", "luggage", "lumber", + "lunar", "lunch", "luxury", "lyrics", "machine", "mad", "magic", "magnet", + "maid", "mail", "main", "major", "make", "mammal", "man", "manage", + "mandate", "mango", "mansion", "manual", "maple", "marble", "march", "margin", + "marine", "market", "marriage", "mask", "mass", "master", "match", "material", + "math", "matrix", "matter", "maximum", "maze", "meadow", "mean", "measure", + "meat", "mechanic", "medal", "media", "melody", "melt", "member", "memory", + "mention", "menu", "mercy", "merge", "merit", "merry", "mesh", "message", + "metal", "method", "middle", "midnight", "milk", "million", "mimic", "mind", + "minimum", "minor", "minute", "miracle", "mirror", "misery", "miss", "mistake", + "mix", "mixed", "mixture", "mobile", "model", "modify", "mom", "moment", + "monitor", "monkey", "monster", "month", "moon", "moral", "more", "morning", + "mosquito", "mother", "motion", "motor", "mountain", "mouse", "move", "movie", + "much", "muffin", "mule", "multiply", "muscle", "museum", "mushroom", "music", + "must", "mutual", "myself", "mystery", "myth", "naive", "name", "napkin", + "narrow", "nasty", "nation", "nature", "near", "neck", "need", "negative", + "neglect", "neither", "nephew", "nerve", "nest", "net", "network", "neutral", + "never", "news", "next", "nice", "night", "noble", "noise", "nominee", + "noodle", "normal", "north", "nose", "notable", "note", "nothing", "notice", + "novel", "now", "nuclear", "number", "nurse", "nut", "oak", "obey", + "object", "oblige", "obscure", "observe", "obtain", "obvious", "occur", "ocean", + "october", "odor", "off", "offer", "office", "often", "oil", "okay", + "old", "olive", "olympic", "omit", "once", "one", "onion", "online", + "only", "open", "opera", "opinion", "oppose", "option", "orange", "orbit", + "orchard", "order", "ordinary", "organ", "orient", "original", "orphan", "ostrich", + "other", "outdoor", "outer", "output", "outside", "oval", "oven", "over", + "own", "owner", "oxygen", "oyster", "ozone", "pact", "paddle", "page", + "pair", "palace", "palm", "panda", "panel", "panic", "panther", "paper", + "parade", "parent", "park", "parrot", "party", "pass", "patch", "path", + "patient", "patrol", "pattern", "pause", "pave", "payment", "peace", "peanut", + "pear", "peasant", "pelican", "pen", "penalty", "pencil", "people", "pepper", + "perfect", "permit", "person", "pet", "phone", "photo", "phrase", "physical", + "piano", "picnic", "picture", "piece", "pig", "pigeon", "pill", "pilot", + "pink", "pioneer", "pipe", "pistol", "pitch", "pizza", "place", "planet", + "plastic", "plate", "play", "please", "pledge", "pluck", "plug", "plunge", + "poem", "poet", "point", "polar", "pole", "police", "pond", "pony", + "pool", "popular", "portion", "position", "possible", "post", "potato", "pottery", + "poverty", "powder", "power", "practice", "praise", "predict", "prefer", "prepare", + "present", "pretty", "prevent", "price", "pride", "primary", "print", "priority", + "prison", "private", "prize", "problem", "process", "produce", "profit", "program", + "project", "promote", "proof", "property", "prosper", "protect", "proud", "provide", + "public", "pudding", "pull", "pulp", "pulse", "pumpkin", "punch", "pupil", + "puppy", "purchase", "purity", "purpose", "purse", "push", "put", "puzzle", + "pyramid", "quality", "quantum", "quarter", "question", "quick", "quit", "quiz", + "quote", "rabbit", "raccoon", "race", "rack", "radar", "radio", "rail", + "rain", "raise", "rally", "ramp", "ranch", "random", "range", "rapid", + "rare", "rate", "rather", "raven", "raw", "razor", "ready", "real", + "reason", "rebel", "rebuild", "recall", "receive", "recipe", "record", "recycle", + "reduce", "reflect", "reform", "refuse", "region", "regret", "regular", "reject", + "relax", "release", "relief", "rely", "remain", "remember", "remind", "remove", + "render", "renew", "rent", "reopen", "repair", "repeat", "replace", "report", + "require", "rescue", "resemble", "resist", "resource", "response", "result", "retire", + "retreat", "return", "reunion", "reveal", "review", "reward", "rhythm", "rib", + "ribbon", "rice", "rich", "ride", "ridge", "rifle", "right", "rigid", + "ring", "riot", "ripple", "risk", "ritual", "rival", "river", "road", + "roast", "robot", "robust", "rocket", "romance", "roof", "rookie", "room", + "rose", "rotate", "rough", "round", "route", "royal", "rubber", "rude", + "rug", "rule", "run", "runway", "rural", "sad", "saddle", "sadness", + "safe", "sail", "salad", "salmon", "salon", "salt", "salute", "same", + "sample", "sand", "satisfy", "satoshi", "sauce", "sausage", "save", "say", + "scale", "scan", "scare", "scatter", "scene", "scheme", "school", "science", + "scissors", "scorpion", "scout", "scrap", "screen", "script", "scrub", "sea", + "search", "season", "seat", "second", "secret", "section", "security", "seed", + "seek", "segment", "select", "sell", "seminar", "senior", "sense", "sentence", + "series", "service", "session", "settle", "setup", "seven", "shadow", "shaft", + "shallow", "share", "shed", "shell", "sheriff", "shield", "shift", "shine", + "ship", "shiver", "shock", "shoe", "shoot", "shop", "short", "shoulder", + "shove", "shrimp", "shrug", "shuffle", "shy", "sibling", "sick", "side", + "siege", "sight", "sign", "silent", "silk", "silly", "silver", "similar", + "simple", "since", "sing", "siren", "sister", "situate", "six", "size", + "skate", "sketch", "ski", "skill", "skin", "skirt", "skull", "slab", + "slam", "sleep", "slender", "slice", "slide", "slight", "slim", "slogan", + "slot", "slow", "slush", "small", "smart", "smile", "smoke", "smooth", + "snack", "snake", "snap", "sniff", "snow", "soap", "soccer", "social", + "sock", "soda", "soft", "solar", "soldier", "solid", "solution", "solve", + "someone", "song", "soon", "sorry", "sort", "soul", "sound", "soup", + "source", "south", "space", "spare", "spatial", "spawn", "speak", "special", + "speed", "spell", "spend", "sphere", "spice", "spider", "spike", "spin", + "spirit", "split", "spoil", "sponsor", "spoon", "sport", "spot", "spray", + "spread", "spring", "spy", "square", "squeeze", "squirrel", "stable", "stadium", + "staff", "stage", "stairs", "stamp", "stand", "start", "state", "stay", + "steak", "steel", "stem", "step", "stereo", "stick", "still", "sting", + "stock", "stomach", "stone", "stool", "story", "stove", "strategy", "street", + "strike", "strong", "struggle", "student", "stuff", "stumble", "style", "subject", + "submit", "subway", "success", "such", "sudden", "suffer", "sugar", "suggest", + "suit", "summer", "sun", "sunny", "sunset", "super", "supply", "supreme", + "sure", "surface", "surge", "surprise", "surround", "survey", "suspect", "sustain", + "swallow", "swamp", "swap", "swarm", "swear", "sweet", "swift", "swim", + "swing", "switch", "sword", "symbol", "symptom", "syrup", "system", "table", + "tackle", "tag", "tail", "talent", "talk", "tank", "tape", "target", + "task", "taste", "tattoo", "taxi", "teach", "team", "tell", "ten", + "tenant", "tennis", "tent", "term", "test", "text", "thank", "that", + "theme", "then", "theory", "there", "they", "thing", "this", "thought", + "three", "thrive", "throw", "thumb", "thunder", "ticket", "tide", "tiger", + "tilt", "timber", "time", "tiny", "tip", "tired", "tissue", "title", + "toast", "tobacco", "today", "toddler", "toe", "together", "toilet", "token", + "tomato", "tomorrow", "tone", "tongue", "tonight", "tool", "tooth", "top", + "topic", "topple", "torch", "tornado", "tortoise", "toss", "total", "tourist", + "toward", "tower", "town", "toy", "track", "trade", "traffic", "tragic", + "train", "transfer", "trap", "trash", "travel", "tray", "treat", "tree", + "trend", "trial", "tribe", "trick", "trigger", "trim", "trip", "trophy", + "trouble", "truck", "true", "truly", "trumpet", "trust", "truth", "try", + "tube", "tuition", "tumble", "tuna", "tunnel", "turkey", "turn", "turtle", + "twelve", "twenty", "twice", "twin", "twist", "two", "type", "typical", + "ugly", "umbrella", "unable", "unaware", "uncle", "uncover", "under", "undo", + "unfair", "unfold", "unhappy", "uniform", "unique", "unit", "universe", "unknown", + "unlock", "until", "unusual", "unveil", "update", "upgrade", "uphold", "upon", + "upper", "upset", "urban", "urge", "usage", "use", "used", "useful", + "useless", "usual", "utility", "vacant", "vacuum", "vague", "valid", "valley", + "valve", "van", "vanish", "vapor", "various", "vast", "vault", "vehicle", + "velvet", "vendor", "venture", "venue", "verb", "verify", "version", "very", + "vessel", "veteran", "viable", "vibrant", "vicious", "victory", "video", "view", + "village", "vintage", "violin", "virtual", "virus", "visa", "visit", "visual", + "vital", "vivid", "vocal", "voice", "void", "volcano", "volume", "vote", + "voyage", "wage", "wagon", "wait", "walk", "wall", "walnut", "want", + "warfare", "warm", "warrior", "wash", "wasp", "waste", "water", "wave", + "way", "wealth", "weapon", "wear", "weasel", "weather", "web", "wedding", + "weekend", "weird", "welcome", "west", "wet", "whale", "what", "wheat", + "wheel", "when", "where", "whip", "whisper", "wide", "width", "wife", + "wild", "will", "win", "window", "wine", "wing", "wink", "winner", + "winter", "wire", "wisdom", "wise", "wish", "witness", "wolf", "woman", + "wonder", "wood", "wool", "word", "work", "world", "worry", "worth", + "wrap", "wreck", "wrestle", "wrist", "write", "wrong", "yard", "year", + "yellow", "you", "young", "youth", "zebra", "zero", "zone", "zoo", +}; diff --git a/applications/external/flipbip/lib/crypto/blake256.c b/applications/external/flipbip/lib/crypto/blake256.c new file mode 100644 index 000000000..dfe6213b6 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/blake256.c @@ -0,0 +1,222 @@ +/* + BLAKE reference C implementation + + Copyright (c) 2012 Jean-Philippe Aumasson + + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + + You should have received a copy of the CC0 Public Domain Dedication along with + this software. If not, see . + */ +#include "blake256.h" + +#include + +#define U8TO32_BIG(p) \ + (((uint32_t)((p)[0]) << 24) | ((uint32_t)((p)[1]) << 16) | ((uint32_t)((p)[2]) << 8) | \ + ((uint32_t)((p)[3]))) + +#define U32TO8_BIG(p, v) \ + (p)[0] = (uint8_t)((v) >> 24); \ + (p)[1] = (uint8_t)((v) >> 16); \ + (p)[2] = (uint8_t)((v) >> 8); \ + (p)[3] = (uint8_t)((v)); + +static const uint8_t sigma[][16] = { + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, + {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4}, + {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8}, + {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13}, + {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9}, + {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11}, + {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10}, + {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5}, + {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, + {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4}, + {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8}, + {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13}, + {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9}}; + +static const uint32_t u256[16] = { + 0x243f6a88, + 0x85a308d3, + 0x13198a2e, + 0x03707344, + 0xa4093822, + 0x299f31d0, + 0x082efa98, + 0xec4e6c89, + 0x452821e6, + 0x38d01377, + 0xbe5466cf, + 0x34e90c6c, + 0xc0ac29b7, + 0xc97c50dd, + 0x3f84d5b5, + 0xb5470917}; + +static const uint8_t padding[129] = {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, 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, 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}; + +static void blake256_compress(BLAKE256_CTX* S, const uint8_t* block) { + uint32_t v[16] = {0}, m[16] = {0}, i = 0; +#define ROT(x, n) (((x) << (32 - n)) | ((x) >> (n))) +#define G(a, b, c, d, e) \ + v[a] += (m[sigma[i][e]] ^ u256[sigma[i][e + 1]]) + v[b]; \ + v[d] = ROT(v[d] ^ v[a], 16); \ + v[c] += v[d]; \ + v[b] = ROT(v[b] ^ v[c], 12); \ + v[a] += (m[sigma[i][e + 1]] ^ u256[sigma[i][e]]) + v[b]; \ + v[d] = ROT(v[d] ^ v[a], 8); \ + v[c] += v[d]; \ + v[b] = ROT(v[b] ^ v[c], 7); + + for(i = 0; i < 16; ++i) m[i] = U8TO32_BIG(block + i * 4); + + for(i = 0; i < 8; ++i) v[i] = S->h[i]; + + v[8] = S->s[0] ^ u256[0]; + v[9] = S->s[1] ^ u256[1]; + v[10] = S->s[2] ^ u256[2]; + v[11] = S->s[3] ^ u256[3]; + v[12] = u256[4]; + v[13] = u256[5]; + v[14] = u256[6]; + v[15] = u256[7]; + + /* don't xor t when the block is only padding */ + if(!S->nullt) { + v[12] ^= S->t[0]; + v[13] ^= S->t[0]; + v[14] ^= S->t[1]; + v[15] ^= S->t[1]; + } + + for(i = 0; i < 14; ++i) { + /* column step */ + G(0, 4, 8, 12, 0); + G(1, 5, 9, 13, 2); + G(2, 6, 10, 14, 4); + G(3, 7, 11, 15, 6); + /* diagonal step */ + G(0, 5, 10, 15, 8); + G(1, 6, 11, 12, 10); + G(2, 7, 8, 13, 12); + G(3, 4, 9, 14, 14); + } + + for(i = 0; i < 16; ++i) S->h[i % 8] ^= v[i]; + + for(i = 0; i < 8; ++i) S->h[i] ^= S->s[i % 4]; +} + +void blake256_Init(BLAKE256_CTX* S) { + S->h[0] = 0x6a09e667; + S->h[1] = 0xbb67ae85; + S->h[2] = 0x3c6ef372; + S->h[3] = 0xa54ff53a; + S->h[4] = 0x510e527f; + S->h[5] = 0x9b05688c; + S->h[6] = 0x1f83d9ab; + S->h[7] = 0x5be0cd19; + S->t[0] = S->t[1] = S->buflen = S->nullt = 0; + S->s[0] = S->s[1] = S->s[2] = S->s[3] = 0; +} + +void blake256_Update(BLAKE256_CTX* S, const uint8_t* in, size_t inlen) { + size_t left = S->buflen; + size_t fill = 64 - left; + + /* data left and data received fill a block */ + if(left && (inlen >= fill)) { + memcpy((void*)(S->buf + left), (void*)in, fill); + S->t[0] += 512; + + if(S->t[0] == 0) S->t[1]++; + + blake256_compress(S, S->buf); + in += fill; + inlen -= fill; + left = 0; + } + + /* compress blocks of data received */ + while(inlen >= 64) { + S->t[0] += 512; + + if(S->t[0] == 0) S->t[1]++; + + blake256_compress(S, in); + in += 64; + inlen -= 64; + } + + /* store any data left */ + if(inlen > 0) { + memcpy((void*)(S->buf + left), (void*)in, (size_t)inlen); + } + S->buflen = left + inlen; +} + +void blake256_Final(BLAKE256_CTX* S, uint8_t* out) { + uint8_t msglen[8] = {0}, zo = 0x01, oo = 0x81; + uint32_t lo = S->t[0] + (S->buflen << 3), hi = S->t[1]; + + /* support for hashing more than 2^32 bits */ + if(lo < (S->buflen << 3)) hi++; + + U32TO8_BIG(msglen + 0, hi); + U32TO8_BIG(msglen + 4, lo); + + if(S->buflen == 55) /* one padding byte */ + { + S->t[0] -= 8; + blake256_Update(S, &oo, 1); + } else { + if(S->buflen < 55) /* enough space to fill the block */ + { + if(!S->buflen) S->nullt = 1; + + S->t[0] -= 440 - (S->buflen << 3); + blake256_Update(S, padding, 55 - S->buflen); + } else /* need 2 compressions */ + { + S->t[0] -= 512 - (S->buflen << 3); + blake256_Update(S, padding, 64 - S->buflen); + S->t[0] -= 440; + blake256_Update(S, padding + 1, 55); + S->nullt = 1; + } + + blake256_Update(S, &zo, 1); + S->t[0] -= 8; + } + + S->t[0] -= 64; + blake256_Update(S, msglen, 8); + U32TO8_BIG(out + 0, S->h[0]); + U32TO8_BIG(out + 4, S->h[1]); + U32TO8_BIG(out + 8, S->h[2]); + U32TO8_BIG(out + 12, S->h[3]); + U32TO8_BIG(out + 16, S->h[4]); + U32TO8_BIG(out + 20, S->h[5]); + U32TO8_BIG(out + 24, S->h[6]); + U32TO8_BIG(out + 28, S->h[7]); +} + +void blake256(const uint8_t* in, size_t inlen, uint8_t* out) { + BLAKE256_CTX S = {0}; + blake256_Init(&S); + blake256_Update(&S, in, inlen); + blake256_Final(&S, out); +} diff --git a/applications/external/flipbip/lib/crypto/blake256.h b/applications/external/flipbip/lib/crypto/blake256.h new file mode 100644 index 000000000..c02f7c004 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/blake256.h @@ -0,0 +1,53 @@ +// Copyright (c) 2014-2017, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#ifndef __BLAKE256_H__ +#define __BLAKE256_H__ + +#include +#include + +#define BLAKE256_DIGEST_LENGTH 32 +#define BLAKE256_BLOCK_LENGTH 64 + +typedef struct { + uint32_t h[8], s[4], t[2]; + size_t buflen; + uint8_t nullt; + uint8_t buf[64]; +} BLAKE256_CTX; + +void blake256_Init(BLAKE256_CTX*); +void blake256_Update(BLAKE256_CTX*, const uint8_t*, size_t); +void blake256_Final(BLAKE256_CTX*, uint8_t*); + +void blake256(const uint8_t*, size_t, uint8_t*); + +#endif /* __BLAKE256_H__ */ diff --git a/applications/external/flipbip/lib/crypto/blake2_common.h b/applications/external/flipbip/lib/crypto/blake2_common.h new file mode 100644 index 000000000..369c7cc0f --- /dev/null +++ b/applications/external/flipbip/lib/crypto/blake2_common.h @@ -0,0 +1,46 @@ + +#include "byte_order.h" + +static inline uint32_t load32(const void* src) { + uint32_t w; + memcpy(&w, src, sizeof w); +#if BYTE_ORDER == BIG_ENDIAN + REVERSE32(w, w); +#endif + return w; +} + +static inline uint64_t load64(const void* src) { + uint64_t w; + memcpy(&w, src, sizeof w); +#if BYTE_ORDER == BIG_ENDIAN + REVERSE64(w, w); +#endif + return w; +} + +static inline void store16(void* dst, uint16_t w) { + memcpy(dst, &w, sizeof w); +} + +static inline void store32(void* dst, uint32_t w) { +#if BYTE_ORDER == BIG_ENDIAN + REVERSE32(w, w); +#endif + memcpy(dst, &w, sizeof w); +} + +static inline void store64(void* dst, uint64_t w) { +#if BYTE_ORDER == BIG_ENDIAN + REVERSE64(w, w); +#endif + memcpy(dst, &w, sizeof w); +} + +static inline uint32_t rotr32(const uint32_t w, const unsigned c) { + return (w >> c) | (w << (32 - c)); +} + +static inline uint64_t rotr64(const uint64_t w, const unsigned c) { + return (w >> c) | (w << (64 - c)); +} diff --git a/applications/external/flipbip/lib/crypto/blake2b.c b/applications/external/flipbip/lib/crypto/blake2b.c new file mode 100644 index 000000000..1f92b66f2 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/blake2b.c @@ -0,0 +1,313 @@ +/* + BLAKE2 reference source code package - reference C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ + +#include + +#include "blake2b.h" +#include "blake2_common.h" +#include "memzero.h" + +typedef struct blake2b_param__ { + uint8_t digest_length; /* 1 */ + uint8_t key_length; /* 2 */ + uint8_t fanout; /* 3 */ + uint8_t depth; /* 4 */ + uint32_t leaf_length; /* 8 */ + uint32_t node_offset; /* 12 */ + uint32_t xof_length; /* 16 */ + uint8_t node_depth; /* 17 */ + uint8_t inner_length; /* 18 */ + uint8_t reserved[14]; /* 32 */ + uint8_t salt[BLAKE2B_SALTBYTES]; /* 48 */ + uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */ +} __attribute__((packed)) blake2b_param; + +static const uint64_t blake2b_IV[8] = { + 0x6a09e667f3bcc908ULL, + 0xbb67ae8584caa73bULL, + 0x3c6ef372fe94f82bULL, + 0xa54ff53a5f1d36f1ULL, + 0x510e527fade682d1ULL, + 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, + 0x5be0cd19137e2179ULL}; + +static const uint8_t blake2b_sigma[12][16] = { + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, + {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4}, + {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8}, + {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13}, + {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9}, + {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11}, + {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10}, + {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5}, + {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}}; + +static void blake2b_set_lastnode(blake2b_state* S) { + S->f[1] = (uint64_t)-1; +} + +/* Some helper functions, not necessarily useful */ +static int blake2b_is_lastblock(const blake2b_state* S) { + return S->f[0] != 0; +} + +static void blake2b_set_lastblock(blake2b_state* S) { + if(S->last_node) blake2b_set_lastnode(S); + + S->f[0] = (uint64_t)-1; +} + +static void blake2b_increment_counter(blake2b_state* S, const uint64_t inc) { + S->t[0] += inc; + S->t[1] += (S->t[0] < inc); +} + +static void blake2b_init0(blake2b_state* S) { + size_t i = 0; + memzero(S, sizeof(blake2b_state)); + + for(i = 0; i < 8; ++i) S->h[i] = blake2b_IV[i]; +} + +/* init xors IV with input parameter block */ +int blake2b_init_param(blake2b_state* S, const blake2b_param* P) { + const uint8_t* p = (const uint8_t*)(P); + size_t i = 0; + + blake2b_init0(S); + + /* IV XOR ParamBlock */ + for(i = 0; i < 8; ++i) S->h[i] ^= load64(p + sizeof(S->h[i]) * i); + + S->outlen = P->digest_length; + return 0; +} + +/* Sequential blake2b initialization */ +int blake2b_Init(blake2b_state* S, size_t outlen) { + blake2b_param P[1] = {0}; + + if((!outlen) || (outlen > BLAKE2B_OUTBYTES)) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = 0; + P->fanout = 1; + P->depth = 1; + store32(&P->leaf_length, 0); + store32(&P->node_offset, 0); + store32(&P->xof_length, 0); + P->node_depth = 0; + P->inner_length = 0; + memzero(P->reserved, sizeof(P->reserved)); + memzero(P->salt, sizeof(P->salt)); + memzero(P->personal, sizeof(P->personal)); + return blake2b_init_param(S, P); +} + +int blake2b_InitPersonal( + blake2b_state* S, + size_t outlen, + const void* personal, + size_t personal_len) { + blake2b_param P[1] = {0}; + + if((!outlen) || (outlen > BLAKE2B_OUTBYTES)) return -1; + if((!personal) || (personal_len != BLAKE2B_PERSONALBYTES)) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = 0; + P->fanout = 1; + P->depth = 1; + store32(&P->leaf_length, 0); + store32(&P->node_offset, 0); + store32(&P->xof_length, 0); + P->node_depth = 0; + P->inner_length = 0; + memzero(P->reserved, sizeof(P->reserved)); + memzero(P->salt, sizeof(P->salt)); + memcpy(P->personal, personal, BLAKE2B_PERSONALBYTES); + return blake2b_init_param(S, P); +} + +int blake2b_InitKey(blake2b_state* S, size_t outlen, const void* key, size_t keylen) { + blake2b_param P[1] = {0}; + + if((!outlen) || (outlen > BLAKE2B_OUTBYTES)) return -1; + + if(!key || !keylen || keylen > BLAKE2B_KEYBYTES) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = (uint8_t)keylen; + P->fanout = 1; + P->depth = 1; + store32(&P->leaf_length, 0); + store32(&P->node_offset, 0); + store32(&P->xof_length, 0); + P->node_depth = 0; + P->inner_length = 0; + memzero(P->reserved, sizeof(P->reserved)); + memzero(P->salt, sizeof(P->salt)); + memzero(P->personal, sizeof(P->personal)); + + if(blake2b_init_param(S, P) < 0) return -1; + + { + uint8_t block[BLAKE2B_BLOCKBYTES] = {0}; + memzero(block, BLAKE2B_BLOCKBYTES); + memcpy(block, key, keylen); + blake2b_Update(S, block, BLAKE2B_BLOCKBYTES); + memzero(block, BLAKE2B_BLOCKBYTES); /* Burn the key from stack */ + } + return 0; +} + +#define G(r, i, a, b, c, d) \ + do { \ + a = a + b + m[blake2b_sigma[r][2 * i + 0]]; \ + d = rotr64(d ^ a, 32); \ + c = c + d; \ + b = rotr64(b ^ c, 24); \ + a = a + b + m[blake2b_sigma[r][2 * i + 1]]; \ + d = rotr64(d ^ a, 16); \ + c = c + d; \ + b = rotr64(b ^ c, 63); \ + } while(0) + +#define ROUND(r) \ + do { \ + G(r, 0, v[0], v[4], v[8], v[12]); \ + G(r, 1, v[1], v[5], v[9], v[13]); \ + G(r, 2, v[2], v[6], v[10], v[14]); \ + G(r, 3, v[3], v[7], v[11], v[15]); \ + G(r, 4, v[0], v[5], v[10], v[15]); \ + G(r, 5, v[1], v[6], v[11], v[12]); \ + G(r, 6, v[2], v[7], v[8], v[13]); \ + G(r, 7, v[3], v[4], v[9], v[14]); \ + } while(0) + +static void blake2b_compress(blake2b_state* S, const uint8_t block[BLAKE2B_BLOCKBYTES]) { + uint64_t m[16] = {0}; + uint64_t v[16] = {0}; + size_t i = 0; + + for(i = 0; i < 16; ++i) { + m[i] = load64(block + i * sizeof(m[i])); + } + + for(i = 0; i < 8; ++i) { + v[i] = S->h[i]; + } + + v[8] = blake2b_IV[0]; + v[9] = blake2b_IV[1]; + v[10] = blake2b_IV[2]; + v[11] = blake2b_IV[3]; + v[12] = blake2b_IV[4] ^ S->t[0]; + v[13] = blake2b_IV[5] ^ S->t[1]; + v[14] = blake2b_IV[6] ^ S->f[0]; + v[15] = blake2b_IV[7] ^ S->f[1]; + + ROUND(0); + ROUND(1); + ROUND(2); + ROUND(3); + ROUND(4); + ROUND(5); + ROUND(6); + ROUND(7); + ROUND(8); + ROUND(9); + ROUND(10); + ROUND(11); + + for(i = 0; i < 8; ++i) { + S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; + } +} + +#undef G +#undef ROUND + +int blake2b_Update(blake2b_state* S, const void* pin, size_t inlen) { + const unsigned char* in = (const unsigned char*)pin; + if(inlen > 0) { + size_t left = S->buflen; + size_t fill = BLAKE2B_BLOCKBYTES - left; + if(inlen > fill) { + S->buflen = 0; + memcpy(S->buf + left, in, fill); /* Fill buffer */ + blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); + blake2b_compress(S, S->buf); /* Compress */ + in += fill; + inlen -= fill; + while(inlen > BLAKE2B_BLOCKBYTES) { + blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); + blake2b_compress(S, in); + in += BLAKE2B_BLOCKBYTES; + inlen -= BLAKE2B_BLOCKBYTES; + } + } + memcpy(S->buf + S->buflen, in, inlen); + S->buflen += inlen; + } + return 0; +} + +int blake2b_Final(blake2b_state* S, void* out, size_t outlen) { + uint8_t buffer[BLAKE2B_OUTBYTES] = {0}; + size_t i = 0; + + if(out == NULL || outlen < S->outlen) return -1; + + if(blake2b_is_lastblock(S)) return -1; + + blake2b_increment_counter(S, S->buflen); + blake2b_set_lastblock(S); + memzero(S->buf + S->buflen, BLAKE2B_BLOCKBYTES - S->buflen); /* Padding */ + blake2b_compress(S, S->buf); + + for(i = 0; i < 8; ++i) /* Output full hash to temp buffer */ + store64(buffer + sizeof(S->h[i]) * i, S->h[i]); + + memcpy(out, buffer, S->outlen); + memzero(buffer, sizeof(buffer)); + return 0; +} + +int blake2b(const uint8_t* msg, uint32_t msg_len, void* out, size_t outlen) { + BLAKE2B_CTX ctx; + if(0 != blake2b_Init(&ctx, outlen)) return -1; + if(0 != blake2b_Update(&ctx, msg, msg_len)) return -1; + if(0 != blake2b_Final(&ctx, out, outlen)) return -1; + return 0; +} + +int blake2b_Key( + const uint8_t* msg, + uint32_t msg_len, + const void* key, + size_t keylen, + void* out, + size_t outlen) { + BLAKE2B_CTX ctx; + if(0 != blake2b_InitKey(&ctx, outlen, key, keylen)) return -1; + if(0 != blake2b_Update(&ctx, msg, msg_len)) return -1; + if(0 != blake2b_Final(&ctx, out, outlen)) return -1; + return 0; +} diff --git a/applications/external/flipbip/lib/crypto/blake2b.h b/applications/external/flipbip/lib/crypto/blake2b.h new file mode 100644 index 000000000..5a47a912c --- /dev/null +++ b/applications/external/flipbip/lib/crypto/blake2b.h @@ -0,0 +1,49 @@ +#ifndef __BLAKE2B_H__ +#define __BLAKE2B_H__ + +#include +#include + +enum blake2b_constant { + BLAKE2B_BLOCKBYTES = 128, + BLAKE2B_OUTBYTES = 64, + BLAKE2B_KEYBYTES = 64, + BLAKE2B_SALTBYTES = 16, + BLAKE2B_PERSONALBYTES = 16 +}; + +typedef struct __blake2b_state { + uint64_t h[8]; + uint64_t t[2]; + uint64_t f[2]; + uint8_t buf[BLAKE2B_BLOCKBYTES]; + size_t buflen; + size_t outlen; + uint8_t last_node; +} blake2b_state; + +#define BLAKE2B_CTX blake2b_state +#define BLAKE2B_BLOCK_LENGTH BLAKE2B_BLOCKBYTES +#define BLAKE2B_DIGEST_LENGTH BLAKE2B_OUTBYTES +#define BLAKE2B_KEY_LENGTH BLAKE2B_KEYBYTES + +int blake2b_Init(blake2b_state* S, size_t outlen); +int blake2b_InitKey(blake2b_state* S, size_t outlen, const void* key, size_t keylen); +int blake2b_InitPersonal( + blake2b_state* S, + size_t outlen, + const void* personal, + size_t personal_len); +int blake2b_Update(blake2b_state* S, const void* pin, size_t inlen); +int blake2b_Final(blake2b_state* S, void* out, size_t outlen); + +int blake2b(const uint8_t* msg, uint32_t msg_len, void* out, size_t outlen); +int blake2b_Key( + const uint8_t* msg, + uint32_t msg_len, + const void* key, + size_t keylen, + void* out, + size_t outlen); + +#endif diff --git a/applications/external/flipbip/lib/crypto/blake2s.c b/applications/external/flipbip/lib/crypto/blake2s.c new file mode 100644 index 000000000..0e75ef7c6 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/blake2s.c @@ -0,0 +1,310 @@ +/* + BLAKE2 reference source code package - reference C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ + +#include + +#include "blake2s.h" +#include "blake2_common.h" +#include "memzero.h" + +typedef struct blake2s_param__ { + uint8_t digest_length; /* 1 */ + uint8_t key_length; /* 2 */ + uint8_t fanout; /* 3 */ + uint8_t depth; /* 4 */ + uint32_t leaf_length; /* 8 */ + uint32_t node_offset; /* 12 */ + uint16_t xof_length; /* 14 */ + uint8_t node_depth; /* 15 */ + uint8_t inner_length; /* 16 */ + /* uint8_t reserved[0]; */ + uint8_t salt[BLAKE2S_SALTBYTES]; /* 24 */ + uint8_t personal[BLAKE2S_PERSONALBYTES]; /* 32 */ +} __attribute__((packed)) blake2s_param; + +static const uint32_t blake2s_IV[8] = { + 0x6A09E667UL, + 0xBB67AE85UL, + 0x3C6EF372UL, + 0xA54FF53AUL, + 0x510E527FUL, + 0x9B05688CUL, + 0x1F83D9ABUL, + 0x5BE0CD19UL}; + +static const uint8_t blake2s_sigma[10][16] = { + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, + {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4}, + {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8}, + {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13}, + {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9}, + {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11}, + {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10}, + {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5}, + {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0}, +}; + +static void blake2s_set_lastnode(blake2s_state* S) { + S->f[1] = (uint32_t)-1; +} + +/* Some helper functions, not necessarily useful */ +static int blake2s_is_lastblock(const blake2s_state* S) { + return S->f[0] != 0; +} + +static void blake2s_set_lastblock(blake2s_state* S) { + if(S->last_node) blake2s_set_lastnode(S); + + S->f[0] = (uint32_t)-1; +} + +static void blake2s_increment_counter(blake2s_state* S, const uint32_t inc) { + S->t[0] += inc; + S->t[1] += (S->t[0] < inc); +} + +static void blake2s_init0(blake2s_state* S) { + size_t i = 0; + memzero(S, sizeof(blake2s_state)); + + for(i = 0; i < 8; ++i) S->h[i] = blake2s_IV[i]; +} + +/* init2 xors IV with input parameter block */ +int blake2s_init_param(blake2s_state* S, const blake2s_param* P) { + const unsigned char* p = (const unsigned char*)(P); + size_t i = 0; + + blake2s_init0(S); + + /* IV XOR ParamBlock */ + for(i = 0; i < 8; ++i) S->h[i] ^= load32(&p[i * 4]); + + S->outlen = P->digest_length; + return 0; +} + +/* Sequential blake2s initialization */ +int blake2s_Init(blake2s_state* S, size_t outlen) { + blake2s_param P[1] = {0}; + + if((!outlen) || (outlen > BLAKE2S_OUTBYTES)) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = 0; + P->fanout = 1; + P->depth = 1; + store32(&P->leaf_length, 0); + store32(&P->node_offset, 0); + store16(&P->xof_length, 0); + P->node_depth = 0; + P->inner_length = 0; + /* memzero(P->reserved, sizeof(P->reserved) ); */ + memzero(P->salt, sizeof(P->salt)); + memzero(P->personal, sizeof(P->personal)); + return blake2s_init_param(S, P); +} + +int blake2s_InitPersonal( + blake2s_state* S, + size_t outlen, + const void* personal, + size_t personal_len) { + blake2s_param P[1] = {0}; + + if((!outlen) || (outlen > BLAKE2S_OUTBYTES)) return -1; + if((!personal) || (personal_len != BLAKE2S_PERSONALBYTES)) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = 0; + P->fanout = 1; + P->depth = 1; + store32(&P->leaf_length, 0); + store32(&P->node_offset, 0); + store16(&P->xof_length, 0); + P->node_depth = 0; + P->inner_length = 0; + /* memzero(P->reserved, sizeof(P->reserved) ); */ + memzero(P->salt, sizeof(P->salt)); + memcpy(P->personal, personal, BLAKE2S_PERSONALBYTES); + return blake2s_init_param(S, P); +} + +int blake2s_InitKey(blake2s_state* S, size_t outlen, const void* key, size_t keylen) { + blake2s_param P[1] = {0}; + + if((!outlen) || (outlen > BLAKE2S_OUTBYTES)) return -1; + + if(!key || !keylen || keylen > BLAKE2S_KEYBYTES) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = (uint8_t)keylen; + P->fanout = 1; + P->depth = 1; + store32(&P->leaf_length, 0); + store32(&P->node_offset, 0); + store16(&P->xof_length, 0); + P->node_depth = 0; + P->inner_length = 0; + /* memzero(P->reserved, sizeof(P->reserved) ); */ + memzero(P->salt, sizeof(P->salt)); + memzero(P->personal, sizeof(P->personal)); + + if(blake2s_init_param(S, P) < 0) return -1; + + { + uint8_t block[BLAKE2S_BLOCKBYTES] = {0}; + memzero(block, BLAKE2S_BLOCKBYTES); + memcpy(block, key, keylen); + blake2s_Update(S, block, BLAKE2S_BLOCKBYTES); + memzero(block, BLAKE2S_BLOCKBYTES); /* Burn the key from stack */ + } + return 0; +} + +#define G(r, i, a, b, c, d) \ + do { \ + a = a + b + m[blake2s_sigma[r][2 * i + 0]]; \ + d = rotr32(d ^ a, 16); \ + c = c + d; \ + b = rotr32(b ^ c, 12); \ + a = a + b + m[blake2s_sigma[r][2 * i + 1]]; \ + d = rotr32(d ^ a, 8); \ + c = c + d; \ + b = rotr32(b ^ c, 7); \ + } while(0) + +#define ROUND(r) \ + do { \ + G(r, 0, v[0], v[4], v[8], v[12]); \ + G(r, 1, v[1], v[5], v[9], v[13]); \ + G(r, 2, v[2], v[6], v[10], v[14]); \ + G(r, 3, v[3], v[7], v[11], v[15]); \ + G(r, 4, v[0], v[5], v[10], v[15]); \ + G(r, 5, v[1], v[6], v[11], v[12]); \ + G(r, 6, v[2], v[7], v[8], v[13]); \ + G(r, 7, v[3], v[4], v[9], v[14]); \ + } while(0) + +static void blake2s_compress(blake2s_state* S, const uint8_t in[BLAKE2S_BLOCKBYTES]) { + uint32_t m[16] = {0}; + uint32_t v[16] = {0}; + size_t i = 0; + + for(i = 0; i < 16; ++i) { + m[i] = load32(in + i * sizeof(m[i])); + } + + for(i = 0; i < 8; ++i) { + v[i] = S->h[i]; + } + + v[8] = blake2s_IV[0]; + v[9] = blake2s_IV[1]; + v[10] = blake2s_IV[2]; + v[11] = blake2s_IV[3]; + v[12] = S->t[0] ^ blake2s_IV[4]; + v[13] = S->t[1] ^ blake2s_IV[5]; + v[14] = S->f[0] ^ blake2s_IV[6]; + v[15] = S->f[1] ^ blake2s_IV[7]; + + ROUND(0); + ROUND(1); + ROUND(2); + ROUND(3); + ROUND(4); + ROUND(5); + ROUND(6); + ROUND(7); + ROUND(8); + ROUND(9); + + for(i = 0; i < 8; ++i) { + S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; + } +} + +#undef G +#undef ROUND + +int blake2s_Update(blake2s_state* S, const void* pin, size_t inlen) { + const unsigned char* in = (const unsigned char*)pin; + if(inlen > 0) { + size_t left = S->buflen; + size_t fill = BLAKE2S_BLOCKBYTES - left; + if(inlen > fill) { + S->buflen = 0; + memcpy(S->buf + left, in, fill); /* Fill buffer */ + blake2s_increment_counter(S, BLAKE2S_BLOCKBYTES); + blake2s_compress(S, S->buf); /* Compress */ + in += fill; + inlen -= fill; + while(inlen > BLAKE2S_BLOCKBYTES) { + blake2s_increment_counter(S, BLAKE2S_BLOCKBYTES); + blake2s_compress(S, in); + in += BLAKE2S_BLOCKBYTES; + inlen -= BLAKE2S_BLOCKBYTES; + } + } + memcpy(S->buf + S->buflen, in, inlen); + S->buflen += inlen; + } + return 0; +} + +int blake2s_Final(blake2s_state* S, void* out, size_t outlen) { + uint8_t buffer[BLAKE2S_OUTBYTES] = {0}; + size_t i = 0; + + if(out == NULL || outlen < S->outlen) return -1; + + if(blake2s_is_lastblock(S)) return -1; + + blake2s_increment_counter(S, (uint32_t)S->buflen); + blake2s_set_lastblock(S); + memzero(S->buf + S->buflen, BLAKE2S_BLOCKBYTES - S->buflen); /* Padding */ + blake2s_compress(S, S->buf); + + for(i = 0; i < 8; ++i) /* Output full hash to temp buffer */ + store32(buffer + sizeof(S->h[i]) * i, S->h[i]); + + memcpy(out, buffer, outlen); + memzero(buffer, sizeof(buffer)); + return 0; +} + +int blake2s(const uint8_t* msg, uint32_t msg_len, void* out, size_t outlen) { + BLAKE2S_CTX ctx; + if(0 != blake2s_Init(&ctx, outlen)) return -1; + if(0 != blake2s_Update(&ctx, msg, msg_len)) return -1; + if(0 != blake2s_Final(&ctx, out, outlen)) return -1; + return 0; +} + +int blake2s_Key( + const uint8_t* msg, + uint32_t msg_len, + const void* key, + size_t keylen, + void* out, + size_t outlen) { + BLAKE2S_CTX ctx; + if(0 != blake2s_InitKey(&ctx, outlen, key, keylen)) return -1; + if(0 != blake2s_Update(&ctx, msg, msg_len)) return -1; + if(0 != blake2s_Final(&ctx, out, outlen)) return -1; + return 0; +} diff --git a/applications/external/flipbip/lib/crypto/blake2s.h b/applications/external/flipbip/lib/crypto/blake2s.h new file mode 100644 index 000000000..452090693 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/blake2s.h @@ -0,0 +1,49 @@ +#ifndef __BLAKE2S_H__ +#define __BLAKE2S_H__ + +#include +#include + +enum blake2s_constant { + BLAKE2S_BLOCKBYTES = 64, + BLAKE2S_OUTBYTES = 32, + BLAKE2S_KEYBYTES = 32, + BLAKE2S_SALTBYTES = 8, + BLAKE2S_PERSONALBYTES = 8 +}; + +typedef struct __blake2s_state { + uint32_t h[8]; + uint32_t t[2]; + uint32_t f[2]; + uint8_t buf[BLAKE2S_BLOCKBYTES]; + uint32_t buflen; + uint8_t outlen; + uint8_t last_node; +} blake2s_state; + +#define BLAKE2S_CTX blake2s_state +#define BLAKE2S_BLOCK_LENGTH BLAKE2S_BLOCKBYTES +#define BLAKE2S_DIGEST_LENGTH BLAKE2S_OUTBYTES +#define BLAKE2S_KEY_LENGTH BLAKE2S_KEYBYTES + +int blake2s_Init(blake2s_state* S, size_t outlen); +int blake2s_InitKey(blake2s_state* S, size_t outlen, const void* key, size_t keylen); +int blake2s_InitPersonal( + blake2s_state* S, + size_t outlen, + const void* personal, + size_t personal_len); +int blake2s_Update(blake2s_state* S, const void* pin, size_t inlen); +int blake2s_Final(blake2s_state* S, void* out, size_t outlen); + +int blake2s(const uint8_t* msg, uint32_t msg_len, void* out, size_t outlen); +int blake2s_Key( + const uint8_t* msg, + uint32_t msg_len, + const void* key, + size_t keylen, + void* out, + size_t outlen); + +#endif diff --git a/applications/external/flipbip/lib/crypto/byte_order.h b/applications/external/flipbip/lib/crypto/byte_order.h new file mode 100644 index 000000000..8484f4349 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/byte_order.h @@ -0,0 +1,57 @@ +#ifndef __BYTE_ORDER_H__ +#define __BYTE_ORDER_H__ + +// FROM sha2.h: +/* + * BYTE_ORDER NOTE: + * + * Please make sure that your system defines BYTE_ORDER. If your + * architecture is little-endian, make sure it also defines + * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are + * equivalent. + * + * If your system does not define the above, then you can do so by + * hand like this: + * + * #define LITTLE_ENDIAN 1234 + * #define BIG_ENDIAN 4321 + * + * And for little-endian machines, add: + * + * #define BYTE_ORDER LITTLE_ENDIAN + * + * Or for big-endian machines: + * + * #define BYTE_ORDER BIG_ENDIAN + * + * The FreeBSD machine this was written on defines BYTE_ORDER + * appropriately by including (which in turn includes + * where the appropriate definitions are actually + * made). + */ + +#ifndef LITTLE_ENDIAN +#define LITTLE_ENDIAN 1234 +#define BIG_ENDIAN 4321 +#endif + +#ifndef BYTE_ORDER +#define BYTE_ORDER LITTLE_ENDIAN +#endif + +#define REVERSE32(w, x) \ + { \ + uint32_t tmp = (w); \ + tmp = (tmp >> 16) | (tmp << 16); \ + (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \ + } + +#define REVERSE64(w, x) \ + { \ + uint64_t tmp = (w); \ + tmp = (tmp >> 32) | (tmp << 32); \ + tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | ((tmp & 0x00ff00ff00ff00ffULL) << 8); \ + (x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | ((tmp & 0x0000ffff0000ffffULL) << 16); \ + } + +#endif diff --git a/applications/external/flipbip/lib/crypto/cardano.c b/applications/external/flipbip/lib/crypto/cardano.c new file mode 100644 index 000000000..8542799a7 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/cardano.c @@ -0,0 +1,307 @@ +/** + * Copyright (c) 2013-2021 SatoshiLabs + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include + +#include "bignum.h" +#include "bip32.h" +#include "cardano.h" +#include "curves.h" +#include "hasher.h" +#include "hmac.h" +#include "memzero.h" +#include "options.h" +#include "pbkdf2.h" +#include "sha2.h" + +#if USE_CARDANO + +#define CARDANO_MAX_NODE_DEPTH 1048576 + +const curve_info ed25519_cardano_info = { + .bip32_name = ED25519_CARDANO_NAME, + .params = NULL, + .hasher_base58 = HASHER_SHA2D, + .hasher_sign = HASHER_SHA2D, + .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_script = HASHER_SHA2, +}; + +static void scalar_multiply8(const uint8_t* src, int bytes, uint8_t* dst) { + uint8_t prev_acc = 0; + for(int i = 0; i < bytes; i++) { + dst[i] = (src[i] << 3) + (prev_acc & 0x7); + prev_acc = src[i] >> 5; + } + dst[bytes] = src[bytes - 1] >> 5; +} + +static void scalar_add_256bits(const uint8_t* src1, const uint8_t* src2, uint8_t* dst) { + uint16_t r = 0; + for(int i = 0; i < 32; i++) { + r = r + (uint16_t)src1[i] + (uint16_t)src2[i]; + dst[i] = r & 0xff; + r >>= 8; + } +} + +static void cardano_ed25519_tweak_bits(uint8_t private_key[32]) { + private_key[0] &= 0xf8; + private_key[31] &= 0x1f; + private_key[31] |= 0x40; +} + +int hdnode_private_ckd_cardano(HDNode* inout, uint32_t index) { + if(inout->curve != &ed25519_cardano_info) { + return 0; + } + + if(inout->depth >= CARDANO_MAX_NODE_DEPTH) { + return 0; + } + + // checks for hardened/non-hardened derivation, keysize 32 means we are + // dealing with public key and thus non-h, keysize 64 is for private key + int keysize = 32; + if(index & 0x80000000) { + keysize = 64; + } + + static CONFIDENTIAL uint8_t data[1 + 64 + 4]; + static CONFIDENTIAL uint8_t z[32 + 32]; + static CONFIDENTIAL uint8_t priv_key[64]; + static CONFIDENTIAL uint8_t res_key[64]; + + write_le(data + keysize + 1, index); + + memcpy(priv_key, inout->private_key, 32); + memcpy(priv_key + 32, inout->private_key_extension, 32); + + if(keysize == 64) { // private derivation + data[0] = 0; + memcpy(data + 1, inout->private_key, 32); + memcpy(data + 1 + 32, inout->private_key_extension, 32); + } else { // public derivation + if(hdnode_fill_public_key(inout) != 0) { + return 0; + } + data[0] = 2; + memcpy(data + 1, inout->public_key + 1, 32); + } + + static CONFIDENTIAL HMAC_SHA512_CTX ctx; + hmac_sha512_Init(&ctx, inout->chain_code, 32); + hmac_sha512_Update(&ctx, data, 1 + keysize + 4); + hmac_sha512_Final(&ctx, z); + + static CONFIDENTIAL uint8_t zl8[32]; + memzero(zl8, 32); + + /* get 8 * Zl */ + scalar_multiply8(z, 28, zl8); + /* Kl = 8*Zl + parent(K)l */ + scalar_add_256bits(zl8, priv_key, res_key); + + /* Kr = Zr + parent(K)r */ + scalar_add_256bits(z + 32, priv_key + 32, res_key + 32); + + memcpy(inout->private_key, res_key, 32); + memcpy(inout->private_key_extension, res_key + 32, 32); + + if(keysize == 64) { + data[0] = 1; + } else { + data[0] = 3; + } + hmac_sha512_Init(&ctx, inout->chain_code, 32); + hmac_sha512_Update(&ctx, data, 1 + keysize + 4); + hmac_sha512_Final(&ctx, z); + + memcpy(inout->chain_code, z + 32, 32); + inout->depth++; + inout->child_num = index; + memzero(inout->public_key, sizeof(inout->public_key)); + + // making sure to wipe our memory + memzero(z, sizeof(z)); + memzero(data, sizeof(data)); + memzero(priv_key, sizeof(priv_key)); + memzero(res_key, sizeof(res_key)); + return 1; +} + +int hdnode_from_secret_cardano(const uint8_t secret[CARDANO_SECRET_LENGTH], HDNode* out) { + memzero(out, sizeof(HDNode)); + out->depth = 0; + out->child_num = 0; + out->curve = &ed25519_cardano_info; + memcpy(out->private_key, secret, 32); + memcpy(out->private_key_extension, secret + 32, 32); + memcpy(out->chain_code, secret + 64, 32); + + cardano_ed25519_tweak_bits(out->private_key); + + out->public_key[0] = 0; + if(hdnode_fill_public_key(out) != 0) { + return 0; + } + + return 1; +} + +// Derives the root Cardano secret from a master secret, aka seed, as defined in +// SLIP-0023. +int secret_from_seed_cardano_slip23( + const uint8_t* seed, + int seed_len, + uint8_t secret_out[CARDANO_SECRET_LENGTH]) { + static CONFIDENTIAL uint8_t I[SHA512_DIGEST_LENGTH]; + static CONFIDENTIAL HMAC_SHA512_CTX ctx; + + hmac_sha512_Init(&ctx, (const uint8_t*)ED25519_CARDANO_NAME, strlen(ED25519_CARDANO_NAME)); + hmac_sha512_Update(&ctx, seed, seed_len); + hmac_sha512_Final(&ctx, I); + + sha512_Raw(I, 32, secret_out); + + memcpy(secret_out + SHA512_DIGEST_LENGTH, I + 32, 32); + cardano_ed25519_tweak_bits(secret_out); + + memzero(I, sizeof(I)); + memzero(&ctx, sizeof(ctx)); + return 1; +} + +// Derives the root Cardano secret from a BIP-32 master secret via the Ledger +// derivation: +// https://github.com/cardano-foundation/CIPs/blob/09d7d8ee1bd64f7e6b20b5a6cae088039dce00cb/CIP-0003/Ledger.md +int secret_from_seed_cardano_ledger( + const uint8_t* seed, + int seed_len, + uint8_t secret_out[CARDANO_SECRET_LENGTH]) { + static CONFIDENTIAL uint8_t chain_code[SHA256_DIGEST_LENGTH]; + static CONFIDENTIAL uint8_t root_key[SHA512_DIGEST_LENGTH]; + static CONFIDENTIAL HMAC_SHA256_CTX ctx; + static CONFIDENTIAL HMAC_SHA512_CTX sctx; + + const uint8_t* intermediate_result = seed; + int intermediate_result_len = seed_len; + do { + // STEP 1: derive a master secret like in BIP-32/SLIP-10 + hmac_sha512_Init(&sctx, (const uint8_t*)ED25519_SEED_NAME, strlen(ED25519_SEED_NAME)); + hmac_sha512_Update(&sctx, intermediate_result, intermediate_result_len); + hmac_sha512_Final(&sctx, root_key); + + // STEP 2: check that the resulting key does not have a particular bit set, + // otherwise iterate like in SLIP-10 + intermediate_result = root_key; + intermediate_result_len = sizeof(root_key); + } while(root_key[31] & 0x20); + + // STEP 3: calculate the chain code as a HMAC-SHA256 of "\x01" + seed, + // key is "ed25519 seed" + hmac_sha256_Init(&ctx, (const unsigned char*)ED25519_SEED_NAME, strlen(ED25519_SEED_NAME)); + hmac_sha256_Update(&ctx, (const unsigned char*)"\x01", 1); + hmac_sha256_Update(&ctx, seed, seed_len); + hmac_sha256_Final(&ctx, chain_code); + + // STEP 4: extract information into output + _Static_assert( + SHA512_DIGEST_LENGTH + SHA256_DIGEST_LENGTH == CARDANO_SECRET_LENGTH, + "Invalid configuration of Cardano secret size"); + memcpy(secret_out, root_key, SHA512_DIGEST_LENGTH); + memcpy(secret_out + SHA512_DIGEST_LENGTH, chain_code, SHA256_DIGEST_LENGTH); + + // STEP 5: tweak bits of the private key + cardano_ed25519_tweak_bits(secret_out); + + memzero(&ctx, sizeof(ctx)); + memzero(&sctx, sizeof(sctx)); + memzero(root_key, sizeof(root_key)); + memzero(chain_code, sizeof(chain_code)); + return 1; +} + +#define CARDANO_ICARUS_STEPS 32 +_Static_assert( + CARDANO_ICARUS_PBKDF2_ROUNDS % CARDANO_ICARUS_STEPS == 0, + "CARDANO_ICARUS_STEPS does not divide CARDANO_ICARUS_PBKDF2_ROUNDS"); +#define CARDANO_ICARUS_ROUNDS_PER_STEP (CARDANO_ICARUS_PBKDF2_ROUNDS / CARDANO_ICARUS_STEPS) + +// Derives the root Cardano HDNode from a passphrase and the entropy encoded in +// a BIP-0039 mnemonic using the Icarus derivation scheme, aka V2 derivation +// scheme: +// https://github.com/cardano-foundation/CIPs/blob/09d7d8ee1bd64f7e6b20b5a6cae088039dce00cb/CIP-0003/Icarus.md +int secret_from_entropy_cardano_icarus( + const uint8_t* pass, + int pass_len, + const uint8_t* entropy, + int entropy_len, + uint8_t secret_out[CARDANO_SECRET_LENGTH], + void (*progress_callback)(uint32_t, uint32_t)) { + static CONFIDENTIAL PBKDF2_HMAC_SHA512_CTX pctx; + static CONFIDENTIAL uint8_t digest[SHA512_DIGEST_LENGTH]; + uint32_t progress = 0; + + // PASS 1: first 64 bytes + pbkdf2_hmac_sha512_Init(&pctx, pass, pass_len, entropy, entropy_len, 1); + if(progress_callback) { + progress_callback(progress, CARDANO_ICARUS_PBKDF2_ROUNDS * 2); + } + for(int i = 0; i < CARDANO_ICARUS_STEPS; i++) { + pbkdf2_hmac_sha512_Update(&pctx, CARDANO_ICARUS_ROUNDS_PER_STEP); + if(progress_callback) { + progress += CARDANO_ICARUS_ROUNDS_PER_STEP; + progress_callback(progress, CARDANO_ICARUS_PBKDF2_ROUNDS * 2); + } + } + pbkdf2_hmac_sha512_Final(&pctx, digest); + + memcpy(secret_out, digest, SHA512_DIGEST_LENGTH); + + // PASS 2: remaining 32 bytes + pbkdf2_hmac_sha512_Init(&pctx, pass, pass_len, entropy, entropy_len, 2); + if(progress_callback) { + progress_callback(progress, CARDANO_ICARUS_PBKDF2_ROUNDS * 2); + } + for(int i = 0; i < CARDANO_ICARUS_STEPS; i++) { + pbkdf2_hmac_sha512_Update(&pctx, CARDANO_ICARUS_ROUNDS_PER_STEP); + if(progress_callback) { + progress += CARDANO_ICARUS_ROUNDS_PER_STEP; + progress_callback(progress, CARDANO_ICARUS_PBKDF2_ROUNDS * 2); + } + } + pbkdf2_hmac_sha512_Final(&pctx, digest); + + memcpy( + secret_out + SHA512_DIGEST_LENGTH, digest, CARDANO_SECRET_LENGTH - SHA512_DIGEST_LENGTH); + + cardano_ed25519_tweak_bits(secret_out); + + memzero(&pctx, sizeof(pctx)); + memzero(digest, sizeof(digest)); + return 1; +} + +#endif // USE_CARDANO diff --git a/applications/external/flipbip/lib/crypto/cardano.h b/applications/external/flipbip/lib/crypto/cardano.h new file mode 100644 index 000000000..761ce978c --- /dev/null +++ b/applications/external/flipbip/lib/crypto/cardano.h @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2013-2021 SatoshiLabs + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __CARDANO_H__ +#define __CARDANO_H__ + +#include +#include +#include "bip32.h" +#include "options.h" + +#if USE_CARDANO + +#define CARDANO_SECRET_LENGTH 96 +#define CARDANO_ICARUS_PBKDF2_ROUNDS 4096 + +extern const curve_info ed25519_cardano_info; + +int hdnode_private_ckd_cardano(HDNode* inout, uint32_t i); + +int secret_from_entropy_cardano_icarus( + const uint8_t* pass, + int pass_len, + const uint8_t* entropy, + int entropy_len, + uint8_t secret_out[CARDANO_SECRET_LENGTH], + void (*progress_callback)(uint32_t current, uint32_t total)); +int secret_from_seed_cardano_ledger( + const uint8_t* seed, + int seed_len, + uint8_t secret_out[CARDANO_SECRET_LENGTH]); +int secret_from_seed_cardano_slip23( + const uint8_t* seed, + int seed_len, + uint8_t secret_out[CARDANO_SECRET_LENGTH]); + +int hdnode_from_secret_cardano(const uint8_t secret[CARDANO_SECRET_LENGTH], HDNode* out); + +#endif // USE_CARDANO + +#endif // __CARDANO_H__ diff --git a/applications/external/flipbip/lib/crypto/cash_addr.c b/applications/external/flipbip/lib/crypto/cash_addr.c new file mode 100644 index 000000000..31656c888 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/cash_addr.c @@ -0,0 +1,188 @@ +/* Copyright (c) 2017 Jochen Hoenicke + * based on code Copyright (c) 2017 Peter Wuille + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include + +#include "cash_addr.h" + +#define MAX_CASHADDR_SIZE 129 +#define MAX_BASE32_SIZE 104 +#define MAX_DATA_SIZE 65 +#define MAX_HRP_SIZE 20 +#define CHECKSUM_SIZE 8 + +uint64_t cashaddr_polymod_step(uint64_t pre) { + uint8_t b = pre >> 35; + return ((pre & 0x7FFFFFFFFULL) << 5) ^ (-((b >> 0) & 1) & 0x98f2bc8e61ULL) ^ + (-((b >> 1) & 1) & 0x79b76d99e2ULL) ^ (-((b >> 2) & 1) & 0xf33e5fb3c4ULL) ^ + (-((b >> 3) & 1) & 0xae2eabe2a8ULL) ^ (-((b >> 4) & 1) & 0x1e4f43e470ULL); +} + +static const char* charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; + +static const int8_t charset_rev[128] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1, -1, 29, + -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, 1, 0, 3, 16, 11, 28, 12, 14, + 6, 4, 2, -1, -1, -1, -1, -1, -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, + 19, -1, 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1}; + +int cash_encode(char* output, const char* hrp, const uint8_t* data, size_t data_len) { + uint64_t chk = 1; + size_t i = 0; + while(hrp[i] != 0) { + int ch = hrp[i]; + if(ch < 33 || ch > 126) { + return 0; + } + *(output++) = ch; + chk = cashaddr_polymod_step(chk) ^ (ch & 0x1f); + ++i; + } + if(i + 1 + data_len + CHECKSUM_SIZE > MAX_CASHADDR_SIZE) { + return 0; + } + chk = cashaddr_polymod_step(chk); + *(output++) = ':'; + for(i = 0; i < data_len; ++i) { + if(*data >> 5) return 0; + chk = cashaddr_polymod_step(chk) ^ (*data); + *(output++) = charset[*(data++)]; + } + for(i = 0; i < CHECKSUM_SIZE; ++i) { + chk = cashaddr_polymod_step(chk); + } + chk ^= 1; + for(i = 0; i < CHECKSUM_SIZE; ++i) { + *(output++) = charset[(chk >> ((CHECKSUM_SIZE - 1 - i) * 5)) & 0x1f]; + } + *output = 0; + return 1; +} + +int cash_decode(char* hrp, uint8_t* data, size_t* data_len, const char* input) { + uint64_t chk = 1; + size_t i = 0; + size_t input_len = strlen(input); + size_t hrp_len = 0; + int have_lower = 0, have_upper = 0; + if(input_len < CHECKSUM_SIZE || input_len > MAX_CASHADDR_SIZE) { + return 0; + } + *data_len = 0; + while(*data_len < input_len && input[(input_len - 1) - *data_len] != ':') { + ++(*data_len); + } + hrp_len = input_len - (1 + *data_len); + if(1 + *data_len >= input_len || hrp_len > MAX_HRP_SIZE || *data_len < CHECKSUM_SIZE || + *data_len > CHECKSUM_SIZE + MAX_BASE32_SIZE) { + return 0; + } + // subtract checksum + *(data_len) -= CHECKSUM_SIZE; + for(i = 0; i < hrp_len; ++i) { + int ch = input[i]; + if(ch < 33 || ch > 126) { + return 0; + } + if(ch >= 'a' && ch <= 'z') { + have_lower = 1; + } else if(ch >= 'A' && ch <= 'Z') { + have_upper = 1; + ch = (ch - 'A') + 'a'; + } + hrp[i] = ch; + chk = cashaddr_polymod_step(chk) ^ (ch & 0x1f); + } + hrp[i] = 0; + chk = cashaddr_polymod_step(chk); + ++i; + while(i < input_len) { + int v = (input[i] & 0x80) ? -1 : charset_rev[(int)input[i]]; + if(input[i] >= 'a' && input[i] <= 'z') have_lower = 1; + if(input[i] >= 'A' && input[i] <= 'Z') have_upper = 1; + if(v == -1) { + return 0; + } + chk = cashaddr_polymod_step(chk) ^ v; + if(i + CHECKSUM_SIZE < input_len) { + data[i - (1 + hrp_len)] = v; + } + ++i; + } + if(have_lower && have_upper) { + return 0; + } + return chk == 1; +} + +static int convert_bits( + uint8_t* out, + size_t* outlen, + int outbits, + const uint8_t* in, + size_t inlen, + int inbits, + int pad) { + uint32_t val = 0; + int bits = 0; + uint32_t maxv = (((uint32_t)1) << outbits) - 1; + while(inlen--) { + val = (val << inbits) | *(in++); + bits += inbits; + while(bits >= outbits) { + bits -= outbits; + out[(*outlen)++] = (val >> bits) & maxv; + } + } + if(pad) { + if(bits) { + out[(*outlen)++] = (val << (outbits - bits)) & maxv; + } + } else if(((val << (outbits - bits)) & maxv) || bits >= inbits) { + return 0; + } + return 1; +} + +int cash_addr_encode(char* output, const char* hrp, const uint8_t* data, size_t data_len) { + uint8_t base32[MAX_BASE32_SIZE] = {0}; + size_t base32len = 0; + if(data_len < 2 || data_len > MAX_DATA_SIZE) return 0; + convert_bits(base32, &base32len, 5, data, data_len, 8, 1); + return cash_encode(output, hrp, base32, base32len); +} + +int cash_addr_decode(uint8_t* witdata, size_t* witdata_len, const char* hrp, const char* addr) { + uint8_t data[MAX_BASE32_SIZE] = {0}; + char hrp_actual[MAX_HRP_SIZE + 1] = {0}; + size_t data_len = 0; + if(!cash_decode(hrp_actual, data, &data_len, addr)) return 0; + if(data_len == 0 || data_len > MAX_BASE32_SIZE) return 0; + if(strncmp(hrp, hrp_actual, MAX_HRP_SIZE + 1) != 0) return 0; + *witdata_len = 0; + if(!convert_bits(witdata, witdata_len, 8, data, data_len, 5, 0)) return 0; + if(*witdata_len < 2 || *witdata_len > MAX_DATA_SIZE) return 0; + return 1; +} diff --git a/applications/external/flipbip/lib/crypto/cash_addr.h b/applications/external/flipbip/lib/crypto/cash_addr.h new file mode 100644 index 000000000..5590b5b87 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/cash_addr.h @@ -0,0 +1,74 @@ +/* Copyright (c) 2017 Jochen Hoenicke, Pieter Wuille + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef _CASH_ADDR_H_ +#define _CASH_ADDR_H_ 1 + +#include + +/** Encode a Cashaddr address + * + * Out: output: Pointer to a buffer of size 105 + strlen(hrp) that will be + * updated to contain the null-terminated address. + * In: hrp: Pointer to the null-terminated human readable part to use + * (chain/network specific). + * prog: Data bytes for the hash (between 21 and 65 bytes). + * prog_len: Number of data bytes in prog. + * Returns 1 if successful. + */ +int cash_addr_encode(char* output, const char* hrp, const uint8_t* prog, size_t prog_len); + +/** Decode a CashAddr address + * + * Out: prog: Pointer to a buffer of size 65 that will be updated to + * contain the witness program bytes. + * prog_len: Pointer to a size_t that will be updated to contain the + * length of bytes in prog. hrp: Pointer to the null-terminated human + * readable part that is expected (chain/network specific). addr: Pointer to + * the null-terminated address. Returns 1 if successful. + */ +int cash_addr_decode(uint8_t* prog, size_t* prog_len, const char* hrp, const char* addr); + +/** Encode a Cash string + * + * Out: output: Pointer to a buffer of size strlen(hrp) + data_len + 8 that + * will be updated to contain the null-terminated Cash string. + * In: hrp : Pointer to the null-terminated human readable part. + * data : Pointer to an array of 5-bit values. + * data_len: Length of the data array. + * Returns 1 if successful. + */ +int cash_encode(char* output, const char* hrp, const uint8_t* data, size_t data_len); + +/** Decode a Cash string + * + * Out: hrp: Pointer to a buffer of size strlen(input) - 6. Will be + * updated to contain the null-terminated human readable part. + * data: Pointer to a buffer of size strlen(input) - 8 that will + * hold the encoded 5-bit data values. + * data_len: Pointer to a size_t that will be updated to be the number + * of entries in data. + * In: input: Pointer to a null-terminated Cash string. + * Returns 1 if succesful. + */ +int cash_decode(char* hrp, uint8_t* data, size_t* data_len, const char* input); + +#endif diff --git a/applications/external/flipbip/lib/crypto/chacha20poly1305/LICENSE b/applications/external/flipbip/lib/crypto/chacha20poly1305/LICENSE new file mode 100644 index 000000000..95404966f --- /dev/null +++ b/applications/external/flipbip/lib/crypto/chacha20poly1305/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (C) 2016 Will Glozer + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/applications/external/flipbip/lib/crypto/chacha20poly1305/chacha20poly1305.c b/applications/external/flipbip/lib/crypto/chacha20poly1305/chacha20poly1305.c new file mode 100644 index 000000000..281dd465a --- /dev/null +++ b/applications/external/flipbip/lib/crypto/chacha20poly1305/chacha20poly1305.c @@ -0,0 +1,63 @@ +// Implementations of the XChaCha20 + Poly1305 and ChaCha20 + Poly1305 +// AEAD constructions with a goal of simplicity and correctness rather +// than performance. + +#include "chacha20poly1305.h" +#include "ecrypt_portable.h" + +void hchacha20(ECRYPT_ctx* x, u8* c); + +// Initialize the XChaCha20 + Poly1305 context for encryption or decryption +// using a 32 byte key and 24 byte nonce. The key and the first 16 bytes of +// the nonce are used as input to HChaCha20 to derive the Chacha20 key. +void xchacha20poly1305_init( + chacha20poly1305_ctx* ctx, + const uint8_t key[32], + const uint8_t nonce[24]) { + unsigned char subkey[32] = {0}; + unsigned char block0[64] = {0}; + ECRYPT_ctx tmp = {0}; + + // Generate the Chacha20 key by applying HChaCha20 to the + // original key and the first 16 bytes of the nonce. + ECRYPT_keysetup(&tmp, key, 256, 16); + tmp.input[12] = U8TO32_LITTLE(nonce + 0); + tmp.input[13] = U8TO32_LITTLE(nonce + 4); + tmp.input[14] = U8TO32_LITTLE(nonce + 8); + tmp.input[15] = U8TO32_LITTLE(nonce + 12); + hchacha20(&tmp, subkey); + + // Initialize Chacha20 with the newly generated key and + // the last 8 bytes of the nonce. + ECRYPT_keysetup(&ctx->chacha20, subkey, 256, 16); + ECRYPT_ivsetup(&ctx->chacha20, nonce + 16); + + // Encrypt 64 bytes of zeros and use the first 32 bytes + // as the Poly1305 key. + ECRYPT_encrypt_bytes(&ctx->chacha20, block0, block0, 64); + poly1305_init(&ctx->poly1305, block0); +} + +// Encrypt n bytes of plaintext where n must be evenly divisible by the +// Chacha20 blocksize of 64, except for the final n bytes of plaintext. +void chacha20poly1305_encrypt(chacha20poly1305_ctx* ctx, const uint8_t* in, uint8_t* out, size_t n) { + ECRYPT_encrypt_bytes(&ctx->chacha20, in, out, n); + poly1305_update(&ctx->poly1305, out, n); +} + +// Decrypt n bytes of ciphertext where n must be evenly divisible by the +// Chacha20 blocksize of 64, except for the final n bytes of ciphertext. +void chacha20poly1305_decrypt(chacha20poly1305_ctx* ctx, const uint8_t* in, uint8_t* out, size_t n) { + poly1305_update(&ctx->poly1305, in, n); + ECRYPT_encrypt_bytes(&ctx->chacha20, in, out, n); +} + +// Include authenticated data in the Poly1305 MAC. +void chacha20poly1305_auth(chacha20poly1305_ctx* ctx, const uint8_t* in, size_t n) { + poly1305_update(&ctx->poly1305, in, n); +} + +// Compute NaCl secretbox-style Poly1305 MAC. +void chacha20poly1305_finish(chacha20poly1305_ctx* ctx, uint8_t mac[16]) { + poly1305_finish(&ctx->poly1305, mac); +} diff --git a/applications/external/flipbip/lib/crypto/chacha20poly1305/chacha20poly1305.h b/applications/external/flipbip/lib/crypto/chacha20poly1305/chacha20poly1305.h new file mode 100644 index 000000000..803772b7d --- /dev/null +++ b/applications/external/flipbip/lib/crypto/chacha20poly1305/chacha20poly1305.h @@ -0,0 +1,22 @@ +#ifndef CHACHA20POLY1305_H +#define CHACHA20POLY1305_H + +#include +#include "ecrypt_sync.h" +#include "poly1305_donna.h" + +typedef struct { + ECRYPT_ctx chacha20; + poly1305_context poly1305; +} chacha20poly1305_ctx; + +void xchacha20poly1305_init( + chacha20poly1305_ctx* ctx, + const uint8_t key[32], + const uint8_t nonce[24]); +void chacha20poly1305_encrypt(chacha20poly1305_ctx* ctx, const uint8_t* in, uint8_t* out, size_t n); +void chacha20poly1305_decrypt(chacha20poly1305_ctx* ctx, const uint8_t* in, uint8_t* out, size_t n); +void chacha20poly1305_auth(chacha20poly1305_ctx* ctx, const uint8_t* in, size_t n); +void chacha20poly1305_finish(chacha20poly1305_ctx* ctx, uint8_t mac[16]); + +#endif // CHACHA20POLY1305_H diff --git a/applications/external/flipbip/lib/crypto/chacha20poly1305/chacha_merged.c b/applications/external/flipbip/lib/crypto/chacha20poly1305/chacha_merged.c new file mode 100644 index 000000000..ee228b471 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/chacha20poly1305/chacha_merged.c @@ -0,0 +1,251 @@ +/* +chacha-merged.c version 20080118 +D. J. Bernstein +Public domain. +*/ + +#include "ecrypt_sync.h" +#include "ecrypt_portable.h" + +#define ROTATE(v, c) (ROTL32(v, c)) +#define XOR(v, w) ((v) ^ (w)) +#define PLUS(v, w) (U32V((v) + (w))) +#define PLUSONE(v) (PLUS((v), 1)) + +#define QUARTERROUND(a, b, c, d) \ + a = PLUS(a, b); \ + d = ROTATE(XOR(d, a), 16); \ + c = PLUS(c, d); \ + b = ROTATE(XOR(b, c), 12); \ + a = PLUS(a, b); \ + d = ROTATE(XOR(d, a), 8); \ + c = PLUS(c, d); \ + b = ROTATE(XOR(b, c), 7); + +void ECRYPT_init(void) { + return; +} + +static const char sigma[16] = "expand 32-byte k"; +static const char tau[16] = "expand 16-byte k"; + +void ECRYPT_keysetup(ECRYPT_ctx* x, const u8* k, u32 kbits, u32 ivbits) { + (void)ivbits; + const char* constants = (const char*)0; + + x->input[4] = U8TO32_LITTLE(k + 0); + x->input[5] = U8TO32_LITTLE(k + 4); + x->input[6] = U8TO32_LITTLE(k + 8); + x->input[7] = U8TO32_LITTLE(k + 12); + if(kbits == 256) { /* recommended */ + k += 16; + constants = sigma; + } else { /* kbits == 128 */ + constants = tau; + } + x->input[8] = U8TO32_LITTLE(k + 0); + x->input[9] = U8TO32_LITTLE(k + 4); + x->input[10] = U8TO32_LITTLE(k + 8); + x->input[11] = U8TO32_LITTLE(k + 12); + x->input[0] = U8TO32_LITTLE(constants + 0); + x->input[1] = U8TO32_LITTLE(constants + 4); + x->input[2] = U8TO32_LITTLE(constants + 8); + x->input[3] = U8TO32_LITTLE(constants + 12); +} + +void ECRYPT_ivsetup(ECRYPT_ctx* x, const u8* iv) { + x->input[12] = 0; + x->input[13] = 0; + x->input[14] = U8TO32_LITTLE(iv + 0); + x->input[15] = U8TO32_LITTLE(iv + 4); +} + +void ECRYPT_ctrsetup(ECRYPT_ctx* x, const u8* ctr) { + x->input[12] = U8TO32_LITTLE(ctr + 0); + x->input[13] = U8TO32_LITTLE(ctr + 4); +} + +void ECRYPT_encrypt_bytes(ECRYPT_ctx* x, const u8* m, u8* c, u32 bytes) { + u32 x0 = 0, x1 = 0, x2 = 0, x3 = 0, x4 = 0, x5 = 0, x6 = 0, x7 = 0, x8 = 0, x9 = 0, x10 = 0, + x11 = 0, x12 = 0, x13 = 0, x14 = 0, x15 = 0; + u32 j0 = 0, j1 = 0, j2 = 0, j3 = 0, j4 = 0, j5 = 0, j6 = 0, j7 = 0, j8 = 0, j9 = 0, j10 = 0, + j11 = 0, j12 = 0, j13 = 0, j14 = 0, j15 = 0; + u8* ctarget = 0; + u8 tmp[64] = {0}; + int i = 0; + + if(!bytes) return; + + j0 = x->input[0]; + j1 = x->input[1]; + j2 = x->input[2]; + j3 = x->input[3]; + j4 = x->input[4]; + j5 = x->input[5]; + j6 = x->input[6]; + j7 = x->input[7]; + j8 = x->input[8]; + j9 = x->input[9]; + j10 = x->input[10]; + j11 = x->input[11]; + j12 = x->input[12]; + j13 = x->input[13]; + j14 = x->input[14]; + j15 = x->input[15]; + + for(;;) { + if(bytes < 64) { + for(i = 0; i < (int)bytes; ++i) tmp[i] = m[i]; + m = tmp; + ctarget = c; + c = tmp; + } + x0 = j0; + x1 = j1; + x2 = j2; + x3 = j3; + x4 = j4; + x5 = j5; + x6 = j6; + x7 = j7; + x8 = j8; + x9 = j9; + x10 = j10; + x11 = j11; + x12 = j12; + x13 = j13; + x14 = j14; + x15 = j15; + for(i = 20; i > 0; i -= 2) { + QUARTERROUND(x0, x4, x8, x12) + QUARTERROUND(x1, x5, x9, x13) + QUARTERROUND(x2, x6, x10, x14) + QUARTERROUND(x3, x7, x11, x15) + QUARTERROUND(x0, x5, x10, x15) + QUARTERROUND(x1, x6, x11, x12) + QUARTERROUND(x2, x7, x8, x13) + QUARTERROUND(x3, x4, x9, x14) + } + x0 = PLUS(x0, j0); + x1 = PLUS(x1, j1); + x2 = PLUS(x2, j2); + x3 = PLUS(x3, j3); + x4 = PLUS(x4, j4); + x5 = PLUS(x5, j5); + x6 = PLUS(x6, j6); + x7 = PLUS(x7, j7); + x8 = PLUS(x8, j8); + x9 = PLUS(x9, j9); + x10 = PLUS(x10, j10); + x11 = PLUS(x11, j11); + x12 = PLUS(x12, j12); + x13 = PLUS(x13, j13); + x14 = PLUS(x14, j14); + x15 = PLUS(x15, j15); + + x0 = XOR(x0, U8TO32_LITTLE(m + 0)); + x1 = XOR(x1, U8TO32_LITTLE(m + 4)); + x2 = XOR(x2, U8TO32_LITTLE(m + 8)); + x3 = XOR(x3, U8TO32_LITTLE(m + 12)); + x4 = XOR(x4, U8TO32_LITTLE(m + 16)); + x5 = XOR(x5, U8TO32_LITTLE(m + 20)); + x6 = XOR(x6, U8TO32_LITTLE(m + 24)); + x7 = XOR(x7, U8TO32_LITTLE(m + 28)); + x8 = XOR(x8, U8TO32_LITTLE(m + 32)); + x9 = XOR(x9, U8TO32_LITTLE(m + 36)); + x10 = XOR(x10, U8TO32_LITTLE(m + 40)); + x11 = XOR(x11, U8TO32_LITTLE(m + 44)); + x12 = XOR(x12, U8TO32_LITTLE(m + 48)); + x13 = XOR(x13, U8TO32_LITTLE(m + 52)); + x14 = XOR(x14, U8TO32_LITTLE(m + 56)); + x15 = XOR(x15, U8TO32_LITTLE(m + 60)); + + j12 = PLUSONE(j12); + if(!j12) { + j13 = PLUSONE(j13); + /* stopping at 2^70 bytes per nonce is user's responsibility */ + } + + U32TO8_LITTLE(c + 0, x0); + U32TO8_LITTLE(c + 4, x1); + U32TO8_LITTLE(c + 8, x2); + U32TO8_LITTLE(c + 12, x3); + U32TO8_LITTLE(c + 16, x4); + U32TO8_LITTLE(c + 20, x5); + U32TO8_LITTLE(c + 24, x6); + U32TO8_LITTLE(c + 28, x7); + U32TO8_LITTLE(c + 32, x8); + U32TO8_LITTLE(c + 36, x9); + U32TO8_LITTLE(c + 40, x10); + U32TO8_LITTLE(c + 44, x11); + U32TO8_LITTLE(c + 48, x12); + U32TO8_LITTLE(c + 52, x13); + U32TO8_LITTLE(c + 56, x14); + U32TO8_LITTLE(c + 60, x15); + + if(bytes <= 64) { + if(bytes < 64) { + for(i = 0; i < (int)bytes; ++i) ctarget[i] = c[i]; + } + x->input[12] = j12; + x->input[13] = j13; + return; + } + bytes -= 64; + c += 64; + m += 64; + } +} + +void ECRYPT_decrypt_bytes(ECRYPT_ctx* x, const u8* c, u8* m, u32 bytes) { + ECRYPT_encrypt_bytes(x, c, m, bytes); +} + +void ECRYPT_keystream_bytes(ECRYPT_ctx* x, u8* stream, u32 bytes) { + u32 i = 0; + for(i = 0; i < bytes; ++i) stream[i] = 0; + ECRYPT_encrypt_bytes(x, stream, stream, bytes); +} + +void hchacha20(ECRYPT_ctx* x, u8* c) { + u32 x0 = 0, x1 = 0, x2 = 0, x3 = 0, x4 = 0, x5 = 0, x6 = 0, x7 = 0, x8 = 0, x9 = 0, x10 = 0, + x11 = 0, x12 = 0, x13 = 0, x14 = 0, x15 = 0; + int i = 0; + + x0 = x->input[0]; + x1 = x->input[1]; + x2 = x->input[2]; + x3 = x->input[3]; + x4 = x->input[4]; + x5 = x->input[5]; + x6 = x->input[6]; + x7 = x->input[7]; + x8 = x->input[8]; + x9 = x->input[9]; + x10 = x->input[10]; + x11 = x->input[11]; + x12 = x->input[12]; + x13 = x->input[13]; + x14 = x->input[14]; + x15 = x->input[15]; + + for(i = 20; i > 0; i -= 2) { + QUARTERROUND(x0, x4, x8, x12) + QUARTERROUND(x1, x5, x9, x13) + QUARTERROUND(x2, x6, x10, x14) + QUARTERROUND(x3, x7, x11, x15) + QUARTERROUND(x0, x5, x10, x15) + QUARTERROUND(x1, x6, x11, x12) + QUARTERROUND(x2, x7, x8, x13) + QUARTERROUND(x3, x4, x9, x14) + } + + U32TO8_LITTLE(c + 0, x0); + U32TO8_LITTLE(c + 4, x1); + U32TO8_LITTLE(c + 8, x2); + U32TO8_LITTLE(c + 12, x3); + U32TO8_LITTLE(c + 16, x12); + U32TO8_LITTLE(c + 20, x13); + U32TO8_LITTLE(c + 24, x14); + U32TO8_LITTLE(c + 28, x15); +} diff --git a/applications/external/flipbip/lib/crypto/chacha20poly1305/ecrypt_config.h b/applications/external/flipbip/lib/crypto/chacha20poly1305/ecrypt_config.h new file mode 100644 index 000000000..40a3a484a --- /dev/null +++ b/applications/external/flipbip/lib/crypto/chacha20poly1305/ecrypt_config.h @@ -0,0 +1,316 @@ +/* ecrypt_config.h */ + +/* *** Normally, it should not be necessary to edit this file. *** */ + +#ifndef ECRYPT_CONFIG +#define ECRYPT_CONFIG + +/* ------------------------------------------------------------------------- */ + +/* Guess the endianness of the target architecture. */ + +/* + * The LITTLE endian machines: + */ +#if defined(__ultrix) /* Older MIPS */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(__alpha) /* Alpha */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(i386) /* x86 (gcc) */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(__i386) /* x86 (gcc) */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(__x86_64) /* x86_64 (gcc) */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(_M_IX86) /* x86 (MSC, Borland) */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(_MSC_VER) /* x86 (surely MSC) */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(__INTEL_COMPILER) /* x86 (surely Intel compiler icl.exe) */ +#define ECRYPT_LITTLE_ENDIAN + +/* + * The BIG endian machines: + */ +#elif defined(__sparc) /* Newer Sparc's */ +#define ECRYPT_BIG_ENDIAN +#elif defined(__powerpc__) /* PowerPC */ +#define ECRYPT_BIG_ENDIAN +#elif defined(__ppc__) /* PowerPC */ +#define ECRYPT_BIG_ENDIAN +#elif defined(__hppa) /* HP-PA */ +#define ECRYPT_BIG_ENDIAN + +/* + * Finally machines with UNKNOWN endianness: + */ +#elif defined(_AIX) /* RS6000 */ +#define ECRYPT_UNKNOWN +#elif defined(__aux) /* 68K */ +#define ECRYPT_UNKNOWN +#elif defined(__dgux) /* 88K (but P6 in latest boxes) */ +#define ECRYPT_UNKNOWN +#elif defined(__sgi) /* Newer MIPS */ +#define ECRYPT_UNKNOWN +#else /* Any other processor */ +#define ECRYPT_UNKNOWN +#endif + +/* ------------------------------------------------------------------------- */ + +/* + * Find minimal-width types to store 8-bit, 16-bit, 32-bit, and 64-bit + * integers. + * + * Note: to enable 64-bit types on 32-bit compilers, it might be + * necessary to switch from ISO C90 mode to ISO C99 mode (e.g., gcc + * -std=c99), or to allow compiler-specific extensions. + */ + +#include + +/* --- check char --- */ + +#if(UCHAR_MAX / 0xFU > 0xFU) +#ifndef I8T +#define I8T char +#define U8C(v) (v##U) + +#if(UCHAR_MAX == 0xFFU) +#define ECRYPT_I8T_IS_BYTE +#endif + +#endif + +#if(UCHAR_MAX / 0xFFU > 0xFFU) +#ifndef I16T +#define I16T char +#define U16C(v) (v##U) +#endif + +#if(UCHAR_MAX / 0xFFFFU > 0xFFFFU) +#ifndef I32T +#define I32T char +#define U32C(v) (v##U) +#endif + +#if(UCHAR_MAX / 0xFFFFFFFFU > 0xFFFFFFFFU) +#ifndef I64T +#define I64T char +#define U64C(v) (v##U) +#define ECRYPT_NATIVE64 +#endif + +#endif +#endif +#endif +#endif + +/* --- check short --- */ + +#if(USHRT_MAX / 0xFU > 0xFU) +#ifndef I8T +#define I8T short +#define U8C(v) (v##U) + +#if(USHRT_MAX == 0xFFU) +#define ECRYPT_I8T_IS_BYTE +#endif + +#endif + +#if(USHRT_MAX / 0xFFU > 0xFFU) +#ifndef I16T +#define I16T short +#define U16C(v) (v##U) +#endif + +#if(USHRT_MAX / 0xFFFFU > 0xFFFFU) +#ifndef I32T +#define I32T short +#define U32C(v) (v##U) +#endif + +#if(USHRT_MAX / 0xFFFFFFFFU > 0xFFFFFFFFU) +#ifndef I64T +#define I64T short +#define U64C(v) (v##U) +#define ECRYPT_NATIVE64 +#endif + +#endif +#endif +#endif +#endif + +/* --- check int --- */ + +#if(UINT_MAX / 0xFU > 0xFU) +#ifndef I8T +#define I8T int +#define U8C(v) (v##U) + +#if(ULONG_MAX == 0xFFU) +#define ECRYPT_I8T_IS_BYTE +#endif + +#endif + +#if(UINT_MAX / 0xFFU > 0xFFU) +#ifndef I16T +#define I16T int +#define U16C(v) (v##U) +#endif + +#if(UINT_MAX / 0xFFFFU > 0xFFFFU) +#ifndef I32T +#define I32T int +#define U32C(v) (v##U) +#endif + +#if(UINT_MAX / 0xFFFFFFFFU > 0xFFFFFFFFU) +#ifndef I64T +#define I64T int +#define U64C(v) (v##U) +#define ECRYPT_NATIVE64 +#endif + +#endif +#endif +#endif +#endif + +/* --- check long --- */ + +#if(ULONG_MAX / 0xFUL > 0xFUL) +#ifndef I8T +#define I8T long +#define U8C(v) (v##UL) + +#if(ULONG_MAX == 0xFFUL) +#define ECRYPT_I8T_IS_BYTE +#endif + +#endif + +#if(ULONG_MAX / 0xFFUL > 0xFFUL) +#ifndef I16T +#define I16T long +#define U16C(v) (v##UL) +#endif + +#if(ULONG_MAX / 0xFFFFUL > 0xFFFFUL) +#ifndef I32T +#define I32T long +#define U32C(v) (v##UL) +#endif + +#if(ULONG_MAX / 0xFFFFFFFFUL > 0xFFFFFFFFUL) +#ifndef I64T +#define I64T long +#define U64C(v) (v##UL) +#define ECRYPT_NATIVE64 +#endif + +#endif +#endif +#endif +#endif + +/* --- check long long --- */ + +#ifdef ULLONG_MAX + +#if(ULLONG_MAX / 0xFULL > 0xFULL) +#ifndef I8T +#define I8T long long +#define U8C(v) (v##ULL) + +#if(ULLONG_MAX == 0xFFULL) +#define ECRYPT_I8T_IS_BYTE +#endif + +#endif + +#if(ULLONG_MAX / 0xFFULL > 0xFFULL) +#ifndef I16T +#define I16T long long +#define U16C(v) (v##ULL) +#endif + +#if(ULLONG_MAX / 0xFFFFULL > 0xFFFFULL) +#ifndef I32T +#define I32T long long +#define U32C(v) (v##ULL) +#endif + +#if(ULLONG_MAX / 0xFFFFFFFFULL > 0xFFFFFFFFULL) +#ifndef I64T +#define I64T long long +#define U64C(v) (v##ULL) +#endif + +#endif +#endif +#endif +#endif + +#endif + +/* --- check __int64 --- */ + +#if !defined(__STDC__) && defined(_UI64_MAX) + +#ifndef I64T +#define I64T __int64 +#define U64C(v) (v##ui64) +#endif + +#endif + +/* --- if platform doesn't announce anything, use most common choices --- */ + +#ifndef I8T +#define I8T char +#define U8C(v) (v##U) +#endif +#ifndef I16T +#define I16T short +#define U16C(v) (v##U) +#endif +#ifndef I32T +#define I32T int +#define U32C(v) (v##U) +#endif +#ifndef I64T +#define I64T long long +#define U64C(v) (v##ULL) +#endif + +/* ------------------------------------------------------------------------- */ + +/* find the largest type on this platform (used for alignment) */ + +#if defined(__SSE__) || (defined(_MSC_VER) && (_MSC_VER >= 1300)) + +#include +#define MAXT __m128 + +#elif defined(__MMX__) + +#include +#define MAXT __m64 + +#elif defined(__ALTIVEC__) + +#define MAXT __vector int + +#else + +#define MAXT long + +#endif + +/* ------------------------------------------------------------------------- */ + +#endif diff --git a/applications/external/flipbip/lib/crypto/chacha20poly1305/ecrypt_machine.h b/applications/external/flipbip/lib/crypto/chacha20poly1305/ecrypt_machine.h new file mode 100644 index 000000000..6773c2571 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/chacha20poly1305/ecrypt_machine.h @@ -0,0 +1,49 @@ +/* ecrypt_machine.h */ + +/* + * This file is included by 'ecrypt_portable.h'. It allows to override + * the default macros for specific platforms. Please carefully check + * the machine code generated by your compiler (with optimisations + * turned on) before deciding to edit this file. + */ + +/* ------------------------------------------------------------------------- */ + +#if(defined(ECRYPT_DEFAULT_ROT) && !defined(ECRYPT_MACHINE_ROT)) + +#define ECRYPT_MACHINE_ROT + +#if(defined(WIN32) && defined(_MSC_VER)) + +#undef ROTL32 +#undef ROTR32 +#undef ROTL64 +#undef ROTR64 + +#include + +#pragma intrinsic(_lrotl) /* compile rotations "inline" */ +#pragma intrinsic(_lrotr) + +#define ROTL32(v, n) _lrotl(v, n) +#define ROTR32(v, n) _lrotr(v, n) +#define ROTL64(v, n) _rotl64(v, n) +#define ROTR64(v, n) _rotr64(v, n) + +#endif + +#endif + +/* ------------------------------------------------------------------------- */ + +#if(defined(ECRYPT_DEFAULT_SWAP) && !defined(ECRYPT_MACHINE_SWAP)) + +#define ECRYPT_MACHINE_SWAP + +/* + * If you want to overwrite the default swap macros, put it here. And so on. + */ + +#endif + +/* ------------------------------------------------------------------------- */ diff --git a/applications/external/flipbip/lib/crypto/chacha20poly1305/ecrypt_portable.h b/applications/external/flipbip/lib/crypto/chacha20poly1305/ecrypt_portable.h new file mode 100644 index 000000000..f5d500114 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/chacha20poly1305/ecrypt_portable.h @@ -0,0 +1,246 @@ +/* ecrypt_portable.h */ + +/* + * WARNING: the conversions defined below are implemented as macros, + * and should be used carefully. They should NOT be used with + * parameters which perform some action. E.g., the following two lines + * are not equivalent: + * + * 1) ++x; y = ROTL32(x, n); + * 2) y = ROTL32(++x, n); + */ + +/* + * *** Please do not edit this file. *** + * + * The default macros can be overridden for specific architectures by + * editing 'ecrypt_machine.h'. + */ + +#ifndef ECRYPT_PORTABLE +#define ECRYPT_PORTABLE + +#include "ecrypt_config.h" +#include "ecrypt_types.h" + +/* ------------------------------------------------------------------------- */ + +/* + * The following macros are used to obtain exact-width results. + */ + +#define U8V(v) ((u8)(v)&U8C(0xFF)) +#define U16V(v) ((u16)(v)&U16C(0xFFFF)) +#define U32V(v) ((u32)(v)&U32C(0xFFFFFFFF)) +#define U64V(v) ((u64)(v)&U64C(0xFFFFFFFFFFFFFFFF)) + +/* ------------------------------------------------------------------------- */ + +/* + * The following macros return words with their bits rotated over n + * positions to the left/right. + */ + +#define ECRYPT_DEFAULT_ROT + +#define ROTL8(v, n) (U8V((v) << (n)) | ((v) >> (8 - (n)))) + +#define ROTL16(v, n) (U16V((v) << (n)) | ((v) >> (16 - (n)))) + +#define ROTL32(v, n) (U32V((v) << (n)) | ((v) >> (32 - (n)))) + +#define ROTL64(v, n) (U64V((v) << (n)) | ((v) >> (64 - (n)))) + +#define ROTR8(v, n) ROTL8(v, 8 - (n)) +#define ROTR16(v, n) ROTL16(v, 16 - (n)) +#define ROTR32(v, n) ROTL32(v, 32 - (n)) +#define ROTR64(v, n) ROTL64(v, 64 - (n)) + +#include "ecrypt_machine.h" + +/* ------------------------------------------------------------------------- */ + +/* + * The following macros return a word with bytes in reverse order. + */ + +#define ECRYPT_DEFAULT_SWAP + +#define SWAP16(v) ROTL16(v, 8) + +#define SWAP32(v) ((ROTL32(v, 8) & U32C(0x00FF00FF)) | (ROTL32(v, 24) & U32C(0xFF00FF00))) + +#ifdef ECRYPT_NATIVE64 +#define SWAP64(v) \ + ((ROTL64(v, 8) & U64C(0x000000FF000000FF)) | (ROTL64(v, 24) & U64C(0x0000FF000000FF00)) | \ + (ROTL64(v, 40) & U64C(0x00FF000000FF0000)) | (ROTL64(v, 56) & U64C(0xFF000000FF000000))) +#else +#define SWAP64(v) (((u64)SWAP32(U32V(v)) << 32) | (u64)SWAP32(U32V(v >> 32))) +#endif + +#include "ecrypt_machine.h" + +#define ECRYPT_DEFAULT_WTOW + +#ifdef ECRYPT_LITTLE_ENDIAN +#define U16TO16_LITTLE(v) (v) +#define U32TO32_LITTLE(v) (v) +#define U64TO64_LITTLE(v) (v) + +#define U16TO16_BIG(v) SWAP16(v) +#define U32TO32_BIG(v) SWAP32(v) +#define U64TO64_BIG(v) SWAP64(v) +#endif + +#ifdef ECRYPT_BIG_ENDIAN +#define U16TO16_LITTLE(v) SWAP16(v) +#define U32TO32_LITTLE(v) SWAP32(v) +#define U64TO64_LITTLE(v) SWAP64(v) + +#define U16TO16_BIG(v) (v) +#define U32TO32_BIG(v) (v) +#define U64TO64_BIG(v) (v) +#endif + +#include "ecrypt_machine.h" + +/* + * The following macros load words from an array of bytes with + * different types of endianness, and vice versa. + */ + +#define ECRYPT_DEFAULT_BTOW + +#if(!defined(ECRYPT_UNKNOWN) && defined(ECRYPT_I8T_IS_BYTE)) + +#define U8TO16_LITTLE(p) U16TO16_LITTLE(((u16*)(p))[0]) +#define U8TO32_LITTLE(p) U32TO32_LITTLE(((u32*)(p))[0]) +#define U8TO64_LITTLE(p) U64TO64_LITTLE(((u64*)(p))[0]) + +#define U8TO16_BIG(p) U16TO16_BIG(((u16*)(p))[0]) +#define U8TO32_BIG(p) U32TO32_BIG(((u32*)(p))[0]) +#define U8TO64_BIG(p) U64TO64_BIG(((u64*)(p))[0]) + +#define U16TO8_LITTLE(p, v) (((u16*)(p))[0] = U16TO16_LITTLE(v)) +#define U32TO8_LITTLE(p, v) (((u32*)(p))[0] = U32TO32_LITTLE(v)) +#define U64TO8_LITTLE(p, v) (((u64*)(p))[0] = U64TO64_LITTLE(v)) + +#define U16TO8_BIG(p, v) (((u16*)(p))[0] = U16TO16_BIG(v)) +#define U32TO8_BIG(p, v) (((u32*)(p))[0] = U32TO32_BIG(v)) +#define U64TO8_BIG(p, v) (((u64*)(p))[0] = U64TO64_BIG(v)) + +#else + +#define U8TO16_LITTLE(p) (((u16)((p)[0])) | ((u16)((p)[1]) << 8)) + +#define U8TO32_LITTLE(p) \ + (((u32)((p)[0])) | ((u32)((p)[1]) << 8) | ((u32)((p)[2]) << 16) | ((u32)((p)[3]) << 24)) + +#ifdef ECRYPT_NATIVE64 +#define U8TO64_LITTLE(p) \ + (((u64)((p)[0])) | ((u64)((p)[1]) << 8) | ((u64)((p)[2]) << 16) | ((u64)((p)[3]) << 24) | \ + ((u64)((p)[4]) << 32) | ((u64)((p)[5]) << 40) | ((u64)((p)[6]) << 48) | \ + ((u64)((p)[7]) << 56)) +#else +#define U8TO64_LITTLE(p) ((u64)U8TO32_LITTLE(p) | ((u64)U8TO32_LITTLE((p) + 4) << 32)) +#endif + +#define U8TO16_BIG(p) (((u16)((p)[0]) << 8) | ((u16)((p)[1]))) + +#define U8TO32_BIG(p) \ + (((u32)((p)[0]) << 24) | ((u32)((p)[1]) << 16) | ((u32)((p)[2]) << 8) | ((u32)((p)[3]))) + +#ifdef ECRYPT_NATIVE64 +#define U8TO64_BIG(p) \ + (((u64)((p)[0]) << 56) | ((u64)((p)[1]) << 48) | ((u64)((p)[2]) << 40) | \ + ((u64)((p)[3]) << 32) | ((u64)((p)[4]) << 24) | ((u64)((p)[5]) << 16) | \ + ((u64)((p)[6]) << 8) | ((u64)((p)[7]))) +#else +#define U8TO64_BIG(p) (((u64)U8TO32_BIG(p) << 32) | (u64)U8TO32_BIG((p) + 4)) +#endif + +#define U16TO8_LITTLE(p, v) \ + do { \ + (p)[0] = U8V((v)); \ + (p)[1] = U8V((v) >> 8); \ + } while(0) + +#define U32TO8_LITTLE(p, v) \ + do { \ + (p)[0] = U8V((v)); \ + (p)[1] = U8V((v) >> 8); \ + (p)[2] = U8V((v) >> 16); \ + (p)[3] = U8V((v) >> 24); \ + } while(0) + +#ifdef ECRYPT_NATIVE64 +#define U64TO8_LITTLE(p, v) \ + do { \ + (p)[0] = U8V((v)); \ + (p)[1] = U8V((v) >> 8); \ + (p)[2] = U8V((v) >> 16); \ + (p)[3] = U8V((v) >> 24); \ + (p)[4] = U8V((v) >> 32); \ + (p)[5] = U8V((v) >> 40); \ + (p)[6] = U8V((v) >> 48); \ + (p)[7] = U8V((v) >> 56); \ + } while(0) +#else +#define U64TO8_LITTLE(p, v) \ + do { \ + U32TO8_LITTLE((p), U32V((v))); \ + U32TO8_LITTLE((p) + 4, U32V((v) >> 32)); \ + } while(0) +#endif + +#define U16TO8_BIG(p, v) \ + do { \ + (p)[0] = U8V((v)); \ + (p)[1] = U8V((v) >> 8); \ + } while(0) + +#define U32TO8_BIG(p, v) \ + do { \ + (p)[0] = U8V((v) >> 24); \ + (p)[1] = U8V((v) >> 16); \ + (p)[2] = U8V((v) >> 8); \ + (p)[3] = U8V((v)); \ + } while(0) + +#ifdef ECRYPT_NATIVE64 +#define U64TO8_BIG(p, v) \ + do { \ + (p)[0] = U8V((v) >> 56); \ + (p)[1] = U8V((v) >> 48); \ + (p)[2] = U8V((v) >> 40); \ + (p)[3] = U8V((v) >> 32); \ + (p)[4] = U8V((v) >> 24); \ + (p)[5] = U8V((v) >> 16); \ + (p)[6] = U8V((v) >> 8); \ + (p)[7] = U8V((v)); \ + } while(0) +#else +#define U64TO8_BIG(p, v) \ + do { \ + U32TO8_BIG((p), U32V((v) >> 32)); \ + U32TO8_BIG((p) + 4, U32V((v))); \ + } while(0) +#endif + +#endif + +#include "ecrypt_machine.h" + +/* ------------------------------------------------------------------------- */ + +#define AT_LEAST_ONE(n) (((n) < 1) ? 1 : (n)) + +#define ALIGN(t, v, n) \ + union { \ + t b[n]; \ + MAXT l[AT_LEAST_ONE(n * sizeof(t) / sizeof(MAXT))]; \ + } v + +/* ------------------------------------------------------------------------- */ + +#endif diff --git a/applications/external/flipbip/lib/crypto/chacha20poly1305/ecrypt_sync.h b/applications/external/flipbip/lib/crypto/chacha20poly1305/ecrypt_sync.h new file mode 100644 index 000000000..f51608f9a --- /dev/null +++ b/applications/external/flipbip/lib/crypto/chacha20poly1305/ecrypt_sync.h @@ -0,0 +1,282 @@ +#define ECRYPT_VARIANT 1 +#define ECRYPT_API +/* ecrypt_sync.h */ + +/* + * Header file for synchronous stream ciphers without authentication + * mechanism. + * + * *** Please only edit parts marked with "[edit]". *** + */ + +#ifndef ECRYPT_SYNC +#define ECRYPT_SYNC + +#include "ecrypt_types.h" + +/* ------------------------------------------------------------------------- */ + +/* Cipher parameters */ + +/* + * The name of your cipher. + */ +#define ECRYPT_NAME "ChaCha20" +#define ECRYPT_PROFILE "_____" + +/* + * Specify which key and IV sizes are supported by your cipher. A user + * should be able to enumerate the supported sizes by running the + * following code: + * + * for (i = 0; ECRYPT_KEYSIZE(i) <= ECRYPT_MAXKEYSIZE; ++i) + * { + * keysize = ECRYPT_KEYSIZE(i); + * + * ... + * } + * + * All sizes are in bits. + */ + +#define ECRYPT_MAXKEYSIZE 256 /* [edit] */ +#define ECRYPT_KEYSIZE(i) (128 + (i)*128) /* [edit] */ + +#define ECRYPT_MAXIVSIZE 64 /* [edit] */ +#define ECRYPT_IVSIZE(i) (64 + (i)*64) /* [edit] */ + +/* ------------------------------------------------------------------------- */ + +/* Data structures */ + +/* + * ECRYPT_ctx is the structure containing the representation of the + * internal state of your cipher. + */ + +typedef struct { + u32 input[16]; /* could be compressed */ + /* + * [edit] + * + * Put here all state variable needed during the encryption process. + */ +} ECRYPT_ctx; + +/* ------------------------------------------------------------------------- */ + +/* Mandatory functions */ + +/* + * Key and message independent initialization. This function will be + * called once when the program starts (e.g., to build expanded S-box + * tables). + */ +void ECRYPT_init(void); + +/* + * Key setup. It is the user's responsibility to select the values of + * keysize and ivsize from the set of supported values specified + * above. + */ +void ECRYPT_keysetup( + ECRYPT_ctx* ctx, + const u8* key, + u32 keysize, /* Key size in bits. */ + u32 ivsize); /* IV size in bits. */ + +/* + * IV setup. After having called ECRYPT_keysetup(), the user is + * allowed to call ECRYPT_ivsetup() different times in order to + * encrypt/decrypt different messages with the same key but different + * IV's. ECRYPT_ivsetup() also sets block counter to zero. + */ +void ECRYPT_ivsetup(ECRYPT_ctx* ctx, const u8* iv); + +/* + * Block counter setup. It is used only for special purposes, + * since block counter is usually initialized with ECRYPT_ivsetup. + * ECRYPT_ctrsetup has to be called after ECRYPT_ivsetup. + */ +void ECRYPT_ctrsetup(ECRYPT_ctx* ctx, const u8* ctr); + +/* + * Encryption/decryption of arbitrary length messages. + * + * For efficiency reasons, the API provides two types of + * encrypt/decrypt functions. The ECRYPT_encrypt_bytes() function + * (declared here) encrypts byte strings of arbitrary length, while + * the ECRYPT_encrypt_blocks() function (defined later) only accepts + * lengths which are multiples of ECRYPT_BLOCKLENGTH. + * + * The user is allowed to make multiple calls to + * ECRYPT_encrypt_blocks() to incrementally encrypt a long message, + * but he is NOT allowed to make additional encryption calls once he + * has called ECRYPT_encrypt_bytes() (unless he starts a new message + * of course). For example, this sequence of calls is acceptable: + * + * ECRYPT_keysetup(); + * + * ECRYPT_ivsetup(); + * ECRYPT_encrypt_blocks(); + * ECRYPT_encrypt_blocks(); + * ECRYPT_encrypt_bytes(); + * + * ECRYPT_ivsetup(); + * ECRYPT_encrypt_blocks(); + * ECRYPT_encrypt_blocks(); + * + * ECRYPT_ivsetup(); + * ECRYPT_encrypt_bytes(); + * + * The following sequence is not: + * + * ECRYPT_keysetup(); + * ECRYPT_ivsetup(); + * ECRYPT_encrypt_blocks(); + * ECRYPT_encrypt_bytes(); + * ECRYPT_encrypt_blocks(); + */ + +void ECRYPT_encrypt_bytes( + ECRYPT_ctx* ctx, + const u8* plaintext, + u8* ciphertext, + u32 msglen); /* Message length in bytes. */ + +void ECRYPT_decrypt_bytes( + ECRYPT_ctx* ctx, + const u8* ciphertext, + u8* plaintext, + u32 msglen); /* Message length in bytes. */ + +/* ------------------------------------------------------------------------- */ + +/* Optional features */ + +/* + * For testing purposes it can sometimes be useful to have a function + * which immediately generates keystream without having to provide it + * with a zero plaintext. If your cipher cannot provide this function + * (e.g., because it is not strictly a synchronous cipher), please + * reset the ECRYPT_GENERATES_KEYSTREAM flag. + */ + +#define ECRYPT_GENERATES_KEYSTREAM +#ifdef ECRYPT_GENERATES_KEYSTREAM + +void ECRYPT_keystream_bytes( + ECRYPT_ctx* ctx, + u8* keystream, + u32 length); /* Length of keystream in bytes. */ + +#endif + +/* ------------------------------------------------------------------------- */ + +/* Optional optimizations */ + +/* + * By default, the functions in this section are implemented using + * calls to functions declared above. However, you might want to + * implement them differently for performance reasons. + */ + +/* + * All-in-one encryption/decryption of (short) packets. + * + * The default definitions of these functions can be found in + * "ecrypt-sync.c". If you want to implement them differently, please + * undef the ECRYPT_USES_DEFAULT_ALL_IN_ONE flag. + */ +#define ECRYPT_USES_DEFAULT_ALL_IN_ONE /* [edit] */ + +void ECRYPT_encrypt_packet( + ECRYPT_ctx* ctx, + const u8* iv, + const u8* plaintext, + u8* ciphertext, + u32 msglen); + +void ECRYPT_decrypt_packet( + ECRYPT_ctx* ctx, + const u8* iv, + const u8* ciphertext, + u8* plaintext, + u32 msglen); + +/* + * Encryption/decryption of blocks. + * + * By default, these functions are defined as macros. If you want to + * provide a different implementation, please undef the + * ECRYPT_USES_DEFAULT_BLOCK_MACROS flag and implement the functions + * declared below. + */ + +#define ECRYPT_BLOCKLENGTH 64 /* [edit] */ + +#define ECRYPT_USES_DEFAULT_BLOCK_MACROS /* [edit] */ +#ifdef ECRYPT_USES_DEFAULT_BLOCK_MACROS + +#define ECRYPT_encrypt_blocks(ctx, plaintext, ciphertext, blocks) \ + ECRYPT_encrypt_bytes(ctx, plaintext, ciphertext, (blocks)*ECRYPT_BLOCKLENGTH) + +#define ECRYPT_decrypt_blocks(ctx, ciphertext, plaintext, blocks) \ + ECRYPT_decrypt_bytes(ctx, ciphertext, plaintext, (blocks)*ECRYPT_BLOCKLENGTH) + +#ifdef ECRYPT_GENERATES_KEYSTREAM + +#define ECRYPT_keystream_blocks(ctx, keystream, blocks) \ + ECRYPT_keystream_bytes(ctx, keystream, (blocks)*ECRYPT_BLOCKLENGTH) + +#endif + +#else + +void ECRYPT_encrypt_blocks( + ECRYPT_ctx* ctx, + const u8* plaintext, + u8* ciphertext, + u32 blocks); /* Message length in blocks. */ + +void ECRYPT_decrypt_blocks( + ECRYPT_ctx* ctx, + const u8* ciphertext, + u8* plaintext, + u32 blocks); /* Message length in blocks. */ + +#ifdef ECRYPT_GENERATES_KEYSTREAM + +void ECRYPT_keystream_blocks( + ECRYPT_ctx* ctx, + const u8* keystream, + u32 blocks); /* Keystream length in blocks. */ + +#endif + +#endif + +/* + * If your cipher can be implemented in different ways, you can use + * the ECRYPT_VARIANT parameter to allow the user to choose between + * them at compile time (e.g., gcc -DECRYPT_VARIANT=3 ...). Please + * only use this possibility if you really think it could make a + * significant difference and keep the number of variants + * (ECRYPT_MAXVARIANT) as small as possible (definitely not more than + * 10). Note also that all variants should have exactly the same + * external interface (i.e., the same ECRYPT_BLOCKLENGTH, etc.). + */ +#define ECRYPT_MAXVARIANT 1 /* [edit] */ + +#ifndef ECRYPT_VARIANT +#define ECRYPT_VARIANT 1 +#endif + +#if(ECRYPT_VARIANT > ECRYPT_MAXVARIANT) +#error this variant does not exist +#endif + +/* ------------------------------------------------------------------------- */ + +#endif diff --git a/applications/external/flipbip/lib/crypto/chacha20poly1305/ecrypt_types.h b/applications/external/flipbip/lib/crypto/chacha20poly1305/ecrypt_types.h new file mode 100644 index 000000000..2d1a41975 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/chacha20poly1305/ecrypt_types.h @@ -0,0 +1,53 @@ +/* ecrypt_types.h */ + +/* + * *** Please do not edit this file. *** + * + * The default macros can be overridden for specific architectures by + * editing 'ecrypt_machine.h'. + */ + +#ifndef ECRYPT_TYPES +#define ECRYPT_TYPES + +#include "ecrypt_config.h" + +/* ------------------------------------------------------------------------- */ + +/* + * The following types are defined (if available): + * + * u8: unsigned integer type, at least 8 bits + * u16: unsigned integer type, at least 16 bits + * u32: unsigned integer type, at least 32 bits + * u64: unsigned integer type, at least 64 bits + * + * s8, s16, s32, s64 -> signed counterparts of u8, u16, u32, u64 + * + * The selection of minimum-width integer types is taken care of by + * 'ecrypt_config.h'. Note: to enable 64-bit types on 32-bit + * compilers, it might be necessary to switch from ISO C90 mode to ISO + * C99 mode (e.g., gcc -std=c99). + */ + +#ifdef I8T +typedef signed I8T s8; +typedef unsigned I8T u8; +#endif + +#ifdef I16T +typedef signed I16T s16; +typedef unsigned I16T u16; +#endif + +#ifdef I32T +typedef signed I32T s32; +typedef unsigned I32T u32; +#endif + +#ifdef I64T +typedef signed I64T s64; +typedef unsigned I64T u64; +#endif + +#endif diff --git a/applications/external/flipbip/lib/crypto/chacha20poly1305/poly1305_donna.c b/applications/external/flipbip/lib/crypto/chacha20poly1305/poly1305_donna.c new file mode 100644 index 000000000..4ab353127 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/chacha20poly1305/poly1305_donna.c @@ -0,0 +1,208 @@ +#include "poly1305_donna.h" +#include "poly1305_donna_32.h" + +void poly1305_update(poly1305_context* ctx, const unsigned char* m, size_t bytes) { + poly1305_state_internal_t* st = (poly1305_state_internal_t*)ctx; + size_t i = 0; + + /* handle leftover */ + if(st->leftover) { + size_t want = (poly1305_block_size - st->leftover); + if(want > bytes) want = bytes; + for(i = 0; i < want; i++) st->buffer[st->leftover + i] = m[i]; + bytes -= want; + m += want; + st->leftover += want; + if(st->leftover < poly1305_block_size) return; + poly1305_blocks(st, st->buffer, poly1305_block_size); + st->leftover = 0; + } + + /* process full blocks */ + if(bytes >= poly1305_block_size) { + size_t want = (bytes & ~(poly1305_block_size - 1)); + poly1305_blocks(st, m, want); + m += want; + bytes -= want; + } + + /* store leftover */ + if(bytes) { + for(i = 0; i < bytes; i++) st->buffer[st->leftover + i] = m[i]; + st->leftover += bytes; + } +} + +void poly1305_auth( + unsigned char mac[16], + const unsigned char* m, + size_t bytes, + const unsigned char key[32]) { + poly1305_context ctx = {0}; + poly1305_init(&ctx, key); + poly1305_update(&ctx, m, bytes); + poly1305_finish(&ctx, mac); +} + +int poly1305_verify(const unsigned char mac1[16], const unsigned char mac2[16]) { + size_t i = 0; + unsigned int dif = 0; + for(i = 0; i < 16; i++) dif |= (mac1[i] ^ mac2[i]); + dif = (dif - 1) >> ((sizeof(unsigned int) * 8) - 1); + return (dif & 1); +} + +/* test a few basic operations */ +int poly1305_power_on_self_test(void) { + /* example from nacl */ + static const unsigned char nacl_key[32] = { + 0xee, 0xa6, 0xa7, 0x25, 0x1c, 0x1e, 0x72, 0x91, 0x6d, 0x11, 0xc2, + 0xcb, 0x21, 0x4d, 0x3c, 0x25, 0x25, 0x39, 0x12, 0x1d, 0x8e, 0x23, + 0x4e, 0x65, 0x2d, 0x65, 0x1f, 0xa4, 0xc8, 0xcf, 0xf8, 0x80, + }; + + static const unsigned char nacl_msg[131] = { + 0x8e, 0x99, 0x3b, 0x9f, 0x48, 0x68, 0x12, 0x73, 0xc2, 0x96, 0x50, 0xba, 0x32, 0xfc, 0x76, + 0xce, 0x48, 0x33, 0x2e, 0xa7, 0x16, 0x4d, 0x96, 0xa4, 0x47, 0x6f, 0xb8, 0xc5, 0x31, 0xa1, + 0x18, 0x6a, 0xc0, 0xdf, 0xc1, 0x7c, 0x98, 0xdc, 0xe8, 0x7b, 0x4d, 0xa7, 0xf0, 0x11, 0xec, + 0x48, 0xc9, 0x72, 0x71, 0xd2, 0xc2, 0x0f, 0x9b, 0x92, 0x8f, 0xe2, 0x27, 0x0d, 0x6f, 0xb8, + 0x63, 0xd5, 0x17, 0x38, 0xb4, 0x8e, 0xee, 0xe3, 0x14, 0xa7, 0xcc, 0x8a, 0xb9, 0x32, 0x16, + 0x45, 0x48, 0xe5, 0x26, 0xae, 0x90, 0x22, 0x43, 0x68, 0x51, 0x7a, 0xcf, 0xea, 0xbd, 0x6b, + 0xb3, 0x73, 0x2b, 0xc0, 0xe9, 0xda, 0x99, 0x83, 0x2b, 0x61, 0xca, 0x01, 0xb6, 0xde, 0x56, + 0x24, 0x4a, 0x9e, 0x88, 0xd5, 0xf9, 0xb3, 0x79, 0x73, 0xf6, 0x22, 0xa4, 0x3d, 0x14, 0xa6, + 0x59, 0x9b, 0x1f, 0x65, 0x4c, 0xb4, 0x5a, 0x74, 0xe3, 0x55, 0xa5}; + + static const unsigned char nacl_mac[16] = { + 0xf3, + 0xff, + 0xc7, + 0x70, + 0x3f, + 0x94, + 0x00, + 0xe5, + 0x2a, + 0x7d, + 0xfb, + 0x4b, + 0x3d, + 0x33, + 0x05, + 0xd9}; + + /* generates a final value of (2^130 - 2) == 3 */ + static const unsigned char wrap_key[32] = { + 0x02, 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, + }; + + static const unsigned char wrap_msg[16] = { + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff}; + + static const unsigned char wrap_mac[16] = { + 0x03, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + }; + + /* + mac of the macs of messages of length 0 to 256, where the key and messages + have all their values set to the length + */ + static const unsigned char total_key[32] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + static const unsigned char total_mac[16] = { + 0x64, + 0xaf, + 0xe2, + 0xe8, + 0xd6, + 0xad, + 0x7b, + 0xbd, + 0xd2, + 0x87, + 0xf9, + 0x7c, + 0x44, + 0x62, + 0x3d, + 0x39}; + + poly1305_context ctx = {0}; + poly1305_context total_ctx = {0}; + unsigned char all_key[32] = {0}; + unsigned char all_msg[256] = {0}; + unsigned char mac[16] = {0}; + size_t i = 0, j = 0; + int result = 1; + + for(i = 0; i < sizeof(mac); i++) mac[i] = 0; + poly1305_auth(mac, nacl_msg, sizeof(nacl_msg), nacl_key); + result &= poly1305_verify(nacl_mac, mac); + + for(i = 0; i < sizeof(mac); i++) mac[i] = 0; + poly1305_init(&ctx, nacl_key); + poly1305_update(&ctx, nacl_msg + 0, 32); + poly1305_update(&ctx, nacl_msg + 32, 64); + poly1305_update(&ctx, nacl_msg + 96, 16); + poly1305_update(&ctx, nacl_msg + 112, 8); + poly1305_update(&ctx, nacl_msg + 120, 4); + poly1305_update(&ctx, nacl_msg + 124, 2); + poly1305_update(&ctx, nacl_msg + 126, 1); + poly1305_update(&ctx, nacl_msg + 127, 1); + poly1305_update(&ctx, nacl_msg + 128, 1); + poly1305_update(&ctx, nacl_msg + 129, 1); + poly1305_update(&ctx, nacl_msg + 130, 1); + poly1305_finish(&ctx, mac); + result &= poly1305_verify(nacl_mac, mac); + + for(i = 0; i < sizeof(mac); i++) mac[i] = 0; + poly1305_auth(mac, wrap_msg, sizeof(wrap_msg), wrap_key); + result &= poly1305_verify(wrap_mac, mac); + + poly1305_init(&total_ctx, total_key); + for(i = 0; i < 256; i++) { + /* set key and message to 'i,i,i..' */ + for(j = 0; j < sizeof(all_key); j++) all_key[j] = i; + for(j = 0; j < i; j++) all_msg[j] = i; + poly1305_auth(mac, all_msg, i, all_key); + poly1305_update(&total_ctx, mac, 16); + } + poly1305_finish(&total_ctx, mac); + result &= poly1305_verify(total_mac, mac); + + return result; +} diff --git a/applications/external/flipbip/lib/crypto/chacha20poly1305/poly1305_donna.h b/applications/external/flipbip/lib/crypto/chacha20poly1305/poly1305_donna.h new file mode 100644 index 000000000..108dee1f6 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/chacha20poly1305/poly1305_donna.h @@ -0,0 +1,23 @@ +#ifndef POLY1305_DONNA_H +#define POLY1305_DONNA_H + +#include + +typedef struct poly1305_context { + size_t aligner; + unsigned char opaque[136]; +} poly1305_context; + +void poly1305_init(poly1305_context* ctx, const unsigned char key[32]); +void poly1305_update(poly1305_context* ctx, const unsigned char* m, size_t bytes); +void poly1305_finish(poly1305_context* ctx, unsigned char mac[16]); +void poly1305_auth( + unsigned char mac[16], + const unsigned char* m, + size_t bytes, + const unsigned char key[32]); + +int poly1305_verify(const unsigned char mac1[16], const unsigned char mac2[16]); +int poly1305_power_on_self_test(void); + +#endif /* POLY1305_DONNA_H */ diff --git a/applications/external/flipbip/lib/crypto/chacha20poly1305/poly1305_donna_32.h b/applications/external/flipbip/lib/crypto/chacha20poly1305/poly1305_donna_32.h new file mode 100644 index 000000000..c2289bb98 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/chacha20poly1305/poly1305_donna_32.h @@ -0,0 +1,252 @@ +/* + poly1305 implementation using 32 bit * 32 bit = 64 bit multiplication and 64 bit addition +*/ + +#if defined(_MSC_VER) +#define POLY1305_NOINLINE __declspec(noinline) +#elif defined(__GNUC__) +#define POLY1305_NOINLINE __attribute__((noinline)) +#else +#define POLY1305_NOINLINE +#endif + +#define poly1305_block_size 16 + +/* 17 + sizeof(size_t) + 14*sizeof(unsigned long) */ +typedef struct poly1305_state_internal_t { + unsigned long r[5]; + unsigned long h[5]; + unsigned long pad[4]; + size_t leftover; + unsigned char buffer[poly1305_block_size]; + unsigned char final; +} poly1305_state_internal_t; + +/* interpret four 8 bit unsigned integers as a 32 bit unsigned integer in little endian */ +static unsigned long U8TO32(const unsigned char* p) { + return ( + ((unsigned long)(p[0] & 0xff)) | ((unsigned long)(p[1] & 0xff) << 8) | + ((unsigned long)(p[2] & 0xff) << 16) | ((unsigned long)(p[3] & 0xff) << 24)); +} + +/* store a 32 bit unsigned integer as four 8 bit unsigned integers in little endian */ +static void U32TO8(unsigned char* p, unsigned long v) { + p[0] = (v)&0xff; + p[1] = (v >> 8) & 0xff; + p[2] = (v >> 16) & 0xff; + p[3] = (v >> 24) & 0xff; +} + +void poly1305_init(poly1305_context* ctx, const unsigned char key[32]) { + poly1305_state_internal_t* st = (poly1305_state_internal_t*)ctx; + + /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ + st->r[0] = (U8TO32(&key[0])) & 0x3ffffff; + st->r[1] = (U8TO32(&key[3]) >> 2) & 0x3ffff03; + st->r[2] = (U8TO32(&key[6]) >> 4) & 0x3ffc0ff; + st->r[3] = (U8TO32(&key[9]) >> 6) & 0x3f03fff; + st->r[4] = (U8TO32(&key[12]) >> 8) & 0x00fffff; + + /* h = 0 */ + st->h[0] = 0; + st->h[1] = 0; + st->h[2] = 0; + st->h[3] = 0; + st->h[4] = 0; + + /* save pad for later */ + st->pad[0] = U8TO32(&key[16]); + st->pad[1] = U8TO32(&key[20]); + st->pad[2] = U8TO32(&key[24]); + st->pad[3] = U8TO32(&key[28]); + + st->leftover = 0; + st->final = 0; +} + +static void poly1305_blocks(poly1305_state_internal_t* st, const unsigned char* m, size_t bytes) { + const unsigned long hibit = (st->final) ? 0 : (1UL << 24); /* 1 << 128 */ + unsigned long r0, r1, r2, r3, r4; + unsigned long s1, s2, s3, s4; + unsigned long h0, h1, h2, h3, h4; + unsigned long long d0, d1, d2, d3, d4; + unsigned long c; + + r0 = st->r[0]; + r1 = st->r[1]; + r2 = st->r[2]; + r3 = st->r[3]; + r4 = st->r[4]; + + s1 = r1 * 5; + s2 = r2 * 5; + s3 = r3 * 5; + s4 = r4 * 5; + + h0 = st->h[0]; + h1 = st->h[1]; + h2 = st->h[2]; + h3 = st->h[3]; + h4 = st->h[4]; + + while(bytes >= poly1305_block_size) { + /* h += m[i] */ + h0 += (U8TO32(m + 0)) & 0x3ffffff; + h1 += (U8TO32(m + 3) >> 2) & 0x3ffffff; + h2 += (U8TO32(m + 6) >> 4) & 0x3ffffff; + h3 += (U8TO32(m + 9) >> 6) & 0x3ffffff; + h4 += (U8TO32(m + 12) >> 8) | hibit; + + /* h *= r */ + d0 = ((unsigned long long)h0 * r0) + ((unsigned long long)h1 * s4) + + ((unsigned long long)h2 * s3) + ((unsigned long long)h3 * s2) + + ((unsigned long long)h4 * s1); + d1 = ((unsigned long long)h0 * r1) + ((unsigned long long)h1 * r0) + + ((unsigned long long)h2 * s4) + ((unsigned long long)h3 * s3) + + ((unsigned long long)h4 * s2); + d2 = ((unsigned long long)h0 * r2) + ((unsigned long long)h1 * r1) + + ((unsigned long long)h2 * r0) + ((unsigned long long)h3 * s4) + + ((unsigned long long)h4 * s3); + d3 = ((unsigned long long)h0 * r3) + ((unsigned long long)h1 * r2) + + ((unsigned long long)h2 * r1) + ((unsigned long long)h3 * r0) + + ((unsigned long long)h4 * s4); + d4 = ((unsigned long long)h0 * r4) + ((unsigned long long)h1 * r3) + + ((unsigned long long)h2 * r2) + ((unsigned long long)h3 * r1) + + ((unsigned long long)h4 * r0); + + /* (partial) h %= p */ + c = (unsigned long)(d0 >> 26); + h0 = (unsigned long)d0 & 0x3ffffff; + d1 += c; + c = (unsigned long)(d1 >> 26); + h1 = (unsigned long)d1 & 0x3ffffff; + d2 += c; + c = (unsigned long)(d2 >> 26); + h2 = (unsigned long)d2 & 0x3ffffff; + d3 += c; + c = (unsigned long)(d3 >> 26); + h3 = (unsigned long)d3 & 0x3ffffff; + d4 += c; + c = (unsigned long)(d4 >> 26); + h4 = (unsigned long)d4 & 0x3ffffff; + h0 += c * 5; + c = (h0 >> 26); + h0 = h0 & 0x3ffffff; + h1 += c; + + m += poly1305_block_size; + bytes -= poly1305_block_size; + } + + st->h[0] = h0; + st->h[1] = h1; + st->h[2] = h2; + st->h[3] = h3; + st->h[4] = h4; +} + +POLY1305_NOINLINE void poly1305_finish(poly1305_context* ctx, unsigned char mac[16]) { + poly1305_state_internal_t* st = (poly1305_state_internal_t*)ctx; + unsigned long h0, h1, h2, h3, h4, c; + unsigned long g0, g1, g2, g3, g4; + unsigned long long f; + unsigned long mask; + + /* process the remaining block */ + if(st->leftover) { + size_t i = st->leftover; + st->buffer[i++] = 1; + for(; i < poly1305_block_size; i++) st->buffer[i] = 0; + st->final = 1; + poly1305_blocks(st, st->buffer, poly1305_block_size); + } + + /* fully carry h */ + h0 = st->h[0]; + h1 = st->h[1]; + h2 = st->h[2]; + h3 = st->h[3]; + h4 = st->h[4]; + + c = h1 >> 26; + h1 = h1 & 0x3ffffff; + h2 += c; + c = h2 >> 26; + h2 = h2 & 0x3ffffff; + h3 += c; + c = h3 >> 26; + h3 = h3 & 0x3ffffff; + h4 += c; + c = h4 >> 26; + h4 = h4 & 0x3ffffff; + h0 += c * 5; + c = h0 >> 26; + h0 = h0 & 0x3ffffff; + h1 += c; + + /* compute h + -p */ + g0 = h0 + 5; + c = g0 >> 26; + g0 &= 0x3ffffff; + g1 = h1 + c; + c = g1 >> 26; + g1 &= 0x3ffffff; + g2 = h2 + c; + c = g2 >> 26; + g2 &= 0x3ffffff; + g3 = h3 + c; + c = g3 >> 26; + g3 &= 0x3ffffff; + g4 = h4 + c - (1UL << 26); + + /* select h if h < p, or h + -p if h >= p */ + mask = (g4 >> ((sizeof(unsigned long) * 8) - 1)) - 1; + g0 &= mask; + g1 &= mask; + g2 &= mask; + g3 &= mask; + g4 &= mask; + mask = ~mask; + h0 = (h0 & mask) | g0; + h1 = (h1 & mask) | g1; + h2 = (h2 & mask) | g2; + h3 = (h3 & mask) | g3; + h4 = (h4 & mask) | g4; + + /* h = h % (2^128) */ + h0 = ((h0) | (h1 << 26)) & 0xffffffff; + h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff; + h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff; + h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff; + + /* mac = (h + pad) % (2^128) */ + f = (unsigned long long)h0 + st->pad[0]; + h0 = (unsigned long)f; + f = (unsigned long long)h1 + st->pad[1] + (f >> 32); + h1 = (unsigned long)f; + f = (unsigned long long)h2 + st->pad[2] + (f >> 32); + h2 = (unsigned long)f; + f = (unsigned long long)h3 + st->pad[3] + (f >> 32); + h3 = (unsigned long)f; + + U32TO8(mac + 0, h0); + U32TO8(mac + 4, h1); + U32TO8(mac + 8, h2); + U32TO8(mac + 12, h3); + + /* zero out the state */ + st->h[0] = 0; + st->h[1] = 0; + st->h[2] = 0; + st->h[3] = 0; + st->h[4] = 0; + st->r[0] = 0; + st->r[1] = 0; + st->r[2] = 0; + st->r[3] = 0; + st->r[4] = 0; + st->pad[0] = 0; + st->pad[1] = 0; + st->pad[2] = 0; + st->pad[3] = 0; +} diff --git a/applications/external/flipbip/lib/crypto/chacha20poly1305/rfc7539.c b/applications/external/flipbip/lib/crypto/chacha20poly1305/rfc7539.c new file mode 100644 index 000000000..f26026fbc --- /dev/null +++ b/applications/external/flipbip/lib/crypto/chacha20poly1305/rfc7539.c @@ -0,0 +1,46 @@ +// Implementation of the ChaCha20 + Poly1305 AEAD construction +// as described in RFC 7539. + +#include +#include "rfc7539.h" +#include "ecrypt_portable.h" + +// Initialize the ChaCha20 + Poly1305 context for encryption or decryption +// using a 32 byte key and 12 byte nonce as in the RFC 7539 style. +void rfc7539_init(chacha20poly1305_ctx* ctx, const uint8_t key[32], const uint8_t nonce[12]) { + unsigned char block0[64] = {0}; + + ECRYPT_keysetup(&ctx->chacha20, key, 256, 16); + ctx->chacha20.input[12] = 0; + ctx->chacha20.input[13] = U8TO32_LITTLE(nonce + 0); + ctx->chacha20.input[14] = U8TO32_LITTLE(nonce + 4); + ctx->chacha20.input[15] = U8TO32_LITTLE(nonce + 8); + + // Encrypt 64 bytes of zeros and use the first 32 bytes + // as the Poly1305 key. + ECRYPT_encrypt_bytes(&ctx->chacha20, block0, block0, 64); + poly1305_init(&ctx->poly1305, block0); +} + +// Include authenticated data in the Poly1305 MAC using the RFC 7539 +// style with 16 byte padding. This must only be called once and prior +// to encryption or decryption. +void rfc7539_auth(chacha20poly1305_ctx* ctx, const uint8_t* in, size_t n) { + uint8_t padding[16] = {0}; + poly1305_update(&ctx->poly1305, in, n); + if(n % 16 != 0) poly1305_update(&ctx->poly1305, padding, 16 - n % 16); +} + +// Compute RFC 7539-style Poly1305 MAC. +void rfc7539_finish(chacha20poly1305_ctx* ctx, int64_t alen, int64_t plen, uint8_t mac[16]) { + uint8_t padding[16] = {0}; + uint8_t lengths[16] = {0}; + + memcpy(lengths, &alen, sizeof(int64_t)); + memcpy(lengths + 8, &plen, sizeof(int64_t)); + + if(plen % 16 != 0) poly1305_update(&ctx->poly1305, padding, 16 - plen % 16); + poly1305_update(&ctx->poly1305, lengths, 16); + + poly1305_finish(&ctx->poly1305, mac); +} diff --git a/applications/external/flipbip/lib/crypto/chacha20poly1305/rfc7539.h b/applications/external/flipbip/lib/crypto/chacha20poly1305/rfc7539.h new file mode 100644 index 000000000..262dc433b --- /dev/null +++ b/applications/external/flipbip/lib/crypto/chacha20poly1305/rfc7539.h @@ -0,0 +1,10 @@ +#ifndef RFC7539_H +#define RFC7539_H + +#include "chacha20poly1305.h" + +void rfc7539_init(chacha20poly1305_ctx* ctx, const uint8_t key[32], const uint8_t nonce[12]); +void rfc7539_auth(chacha20poly1305_ctx* ctx, const uint8_t* in, size_t n); +void rfc7539_finish(chacha20poly1305_ctx* ctx, int64_t alen, int64_t plen, uint8_t mac[16]); + +#endif // RFC7539_H diff --git a/applications/external/flipbip/lib/crypto/chacha_drbg.c b/applications/external/flipbip/lib/crypto/chacha_drbg.c new file mode 100644 index 000000000..fe9b5fd40 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/chacha_drbg.c @@ -0,0 +1,131 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "chacha_drbg.h" + +#include +#include +#include + +#include "chacha20poly1305/ecrypt_portable.h" +#include "memzero.h" +#include "sha2.h" + +#define CHACHA_DRBG_KEY_LENGTH 32 +#define CHACHA_DRBG_COUNTER_LENGTH 8 +#define CHACHA_DRBG_IV_LENGTH 8 +#define CHACHA_DRBG_SEED_LENGTH \ + (CHACHA_DRBG_KEY_LENGTH + CHACHA_DRBG_COUNTER_LENGTH + CHACHA_DRBG_IV_LENGTH) + +#define MAX(a, b) (a) > (b) ? (a) : (b) + +static void derivation_function( + const uint8_t* input1, + size_t input1_length, + const uint8_t* input2, + size_t input2_length, + uint8_t* output, + size_t output_length) { + // Implementation of Hash_df from NIST SP 800-90A + uint32_t block_count = (output_length - 1) / SHA256_DIGEST_LENGTH + 1; + size_t partial_block_length = output_length % SHA256_DIGEST_LENGTH; + assert(block_count <= 255); + + uint32_t output_length_bits = output_length * 8; +#if BYTE_ORDER == LITTLE_ENDIAN + REVERSE32(output_length_bits, output_length_bits); +#endif + + SHA256_CTX ctx = {0}; + + for(uint8_t counter = 1; counter <= block_count; counter++) { + sha256_Init(&ctx); + sha256_Update(&ctx, &counter, sizeof(counter)); + sha256_Update(&ctx, (uint8_t*)&output_length_bits, sizeof(output_length_bits)); + sha256_Update(&ctx, input1, input1_length); + sha256_Update(&ctx, input2, input2_length); + + if(counter != block_count || partial_block_length == 0) { + sha256_Final(&ctx, output); + output += SHA256_DIGEST_LENGTH; + } else { // last block is partial + uint8_t digest[SHA256_DIGEST_LENGTH] = {0}; + sha256_Final(&ctx, digest); + memcpy(output, digest, partial_block_length); + memzero(digest, sizeof(digest)); + } + } + + memzero(&ctx, sizeof(ctx)); +} + +void chacha_drbg_init( + CHACHA_DRBG_CTX* ctx, + const uint8_t* entropy, + size_t entropy_length, + const uint8_t* nonce, + size_t nonce_length) { + uint8_t buffer[MAX(CHACHA_DRBG_KEY_LENGTH, CHACHA_DRBG_IV_LENGTH)] = {0}; + ECRYPT_keysetup( + &ctx->chacha_ctx, buffer, CHACHA_DRBG_KEY_LENGTH * 8, CHACHA_DRBG_IV_LENGTH * 8); + ECRYPT_ivsetup(&ctx->chacha_ctx, buffer); + + chacha_drbg_reseed(ctx, entropy, entropy_length, nonce, nonce_length); +} + +static void chacha_drbg_update(CHACHA_DRBG_CTX* ctx, const uint8_t data[CHACHA_DRBG_SEED_LENGTH]) { + uint8_t seed[CHACHA_DRBG_SEED_LENGTH] = {0}; + + if(data) + ECRYPT_encrypt_bytes(&ctx->chacha_ctx, data, seed, CHACHA_DRBG_SEED_LENGTH); + else + ECRYPT_keystream_bytes(&ctx->chacha_ctx, seed, CHACHA_DRBG_SEED_LENGTH); + + ECRYPT_keysetup(&ctx->chacha_ctx, seed, CHACHA_DRBG_KEY_LENGTH * 8, CHACHA_DRBG_IV_LENGTH * 8); + + ECRYPT_ivsetup(&ctx->chacha_ctx, seed + CHACHA_DRBG_KEY_LENGTH + CHACHA_DRBG_COUNTER_LENGTH); + + ECRYPT_ctrsetup(&ctx->chacha_ctx, seed + CHACHA_DRBG_KEY_LENGTH); + + memzero(seed, sizeof(seed)); +} + +void chacha_drbg_generate(CHACHA_DRBG_CTX* ctx, uint8_t* output, size_t output_length) { + assert(output_length < 65536); + assert(ctx->reseed_counter + 1 != 0); + + ECRYPT_keystream_bytes(&ctx->chacha_ctx, output, output_length); + chacha_drbg_update(ctx, NULL); + ctx->reseed_counter++; +} + +void chacha_drbg_reseed( + CHACHA_DRBG_CTX* ctx, + const uint8_t* entropy, + size_t entropy_length, + const uint8_t* additional_input, + size_t additional_input_length) { + uint8_t seed[CHACHA_DRBG_SEED_LENGTH] = {0}; + derivation_function( + entropy, entropy_length, additional_input, additional_input_length, seed, sizeof(seed)); + chacha_drbg_update(ctx, seed); + memzero(seed, sizeof(seed)); + + ctx->reseed_counter = 1; +} diff --git a/applications/external/flipbip/lib/crypto/chacha_drbg.h b/applications/external/flipbip/lib/crypto/chacha_drbg.h new file mode 100644 index 000000000..740c11c6c --- /dev/null +++ b/applications/external/flipbip/lib/crypto/chacha_drbg.h @@ -0,0 +1,59 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __CHACHA_DRBG__ +#define __CHACHA_DRBG__ + +#include "chacha20poly1305/chacha20poly1305.h" +#include "sha2.h" + +// A very fast deterministic random bit generator based on CTR_DRBG in NIST SP +// 800-90A. Chacha is used instead of a block cipher in the counter mode, SHA256 +// is used as a derivation function. The highest supported security strength is +// at least 256 bits. Reseeding is left up to caller. + +// Length of inputs of chacha_drbg_init (entropy and nonce) or +// chacha_drbg_reseed (entropy and additional_input) that fill exactly +// block_count blocks of hash function in derivation_function. There is no need +// the input to have this length, it's just an optimalization. +#define CHACHA_DRBG_OPTIMAL_RESEED_LENGTH(block_count) \ + ((block_count)*SHA256_BLOCK_LENGTH - 1 - 4 - 9) +// 1 = sizeof(counter), 4 = sizeof(output_length) in +// derivation_function, 9 is length of SHA256 padding of message +// aligned to bytes + +typedef struct _CHACHA_DRBG_CTX { + ECRYPT_ctx chacha_ctx; + uint32_t reseed_counter; +} CHACHA_DRBG_CTX; + +void chacha_drbg_init( + CHACHA_DRBG_CTX* ctx, + const uint8_t* entropy, + size_t entropy_length, + const uint8_t* nonce, + size_t nonce_length); +void chacha_drbg_generate(CHACHA_DRBG_CTX* ctx, uint8_t* output, size_t output_length); +void chacha_drbg_reseed( + CHACHA_DRBG_CTX* ctx, + const uint8_t* entropy, + size_t entropy_length, + const uint8_t* additional_input, + size_t additional_input_length); +#endif // __CHACHA_DRBG__ diff --git a/applications/external/flipbip/lib/crypto/check_mem.h b/applications/external/flipbip/lib/crypto/check_mem.h new file mode 100644 index 000000000..ef8f8c79a --- /dev/null +++ b/applications/external/flipbip/lib/crypto/check_mem.h @@ -0,0 +1,34 @@ +#ifndef CHECK_MEM_H +#define CHECK_MEM_H + +#if CHECK_MAJOR_VERSION == 0 && CHECK_MINOR_VERSION < 11 + +#define _ck_assert_mem(X, Y, L, OP) \ + do { \ + const char* _ck_x = (const char*)(void*)(X); \ + const char* _ck_y = (const char*)(void*)(Y); \ + size_t _ck_l = (L); \ + char _ck_x_str[129]; \ + char _ck_y_str[129]; \ + static char _ck_hexdigits[] = "0123456789abcdef"; \ + size_t _ck_i; \ + for(_ck_i = 0; _ck_i < ((_ck_l > 64) ? 64 : _ck_l); _ck_i++) { \ + _ck_x_str[_ck_i * 2] = _ck_hexdigits[(_ck_x[_ck_i] >> 4) & 0xF]; \ + _ck_y_str[_ck_i * 2] = _ck_hexdigits[(_ck_y[_ck_i] >> 4) & 0xF]; \ + _ck_x_str[_ck_i * 2 + 1] = _ck_hexdigits[_ck_x[_ck_i] & 0xF]; \ + _ck_y_str[_ck_i * 2 + 1] = _ck_hexdigits[_ck_y[_ck_i] & 0xF]; \ + } \ + _ck_x_str[_ck_i * 2] = 0; \ + _ck_y_str[_ck_i * 2] = 0; \ + ck_assert_msg( \ + 0 OP memcmp(_ck_y, _ck_x, _ck_l), \ + "Assertion '" #X #OP #Y "' failed: " #X "==\"%s\", " #Y "==\"%s\"", \ + _ck_x_str, \ + _ck_y_str); \ + } while(0) +#define ck_assert_mem_eq(X, Y, L) _ck_assert_mem(X, Y, L, ==) +#define ck_assert_mem_ne(X, Y, L) _ck_assert_mem(X, Y, L, !=) + +#endif + +#endif diff --git a/applications/external/flipbip/lib/crypto/curves.c b/applications/external/flipbip/lib/crypto/curves.c new file mode 100644 index 000000000..dcdaf7ba4 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/curves.c @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2016 Jochen Hoenicke + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "curves.h" + +const char SECP256K1_NAME[] = "secp256k1"; +const char SECP256K1_DECRED_NAME[] = "secp256k1-decred"; +const char SECP256K1_GROESTL_NAME[] = "secp256k1-groestl"; +const char SECP256K1_SMART_NAME[] = "secp256k1-smart"; +const char NIST256P1_NAME[] = "nist256p1"; +const char ED25519_NAME[] = "ed25519"; +const char ED25519_SEED_NAME[] = "ed25519 seed"; +#if USE_CARDANO +const char ED25519_CARDANO_NAME[] = "ed25519 cardano seed"; +#endif +const char ED25519_SHA3_NAME[] = "ed25519-sha3"; +#if USE_KECCAK +const char ED25519_KECCAK_NAME[] = "ed25519-keccak"; +#endif +const char CURVE25519_NAME[] = "curve25519"; diff --git a/applications/external/flipbip/lib/crypto/curves.h b/applications/external/flipbip/lib/crypto/curves.h new file mode 100644 index 000000000..aabf5b369 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/curves.h @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2016 Jochen Hoenicke + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __CURVES_H__ +#define __CURVES_H__ + +#include "options.h" + +extern const char SECP256K1_NAME[]; +extern const char SECP256K1_DECRED_NAME[]; +extern const char SECP256K1_GROESTL_NAME[]; +extern const char SECP256K1_SMART_NAME[]; +extern const char NIST256P1_NAME[]; +extern const char ED25519_NAME[]; +extern const char ED25519_SEED_NAME[]; +extern const char ED25519_CARDANO_NAME[]; +extern const char ED25519_SHA3_NAME[]; +#if USE_KECCAK +extern const char ED25519_KECCAK_NAME[]; +#endif +extern const char CURVE25519_NAME[]; + +#endif diff --git a/applications/external/flipbip/lib/crypto/ecdsa.c b/applications/external/flipbip/lib/crypto/ecdsa.c new file mode 100644 index 000000000..80ab76b49 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/ecdsa.c @@ -0,0 +1,1284 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * Copyright (c) 2015 Jochen Hoenicke + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include "address.h" +#include "base58.h" +#include "bignum.h" +#include "ecdsa.h" +#include "hmac.h" +#include "memzero.h" +#include "rand.h" +#include "rfc6979.h" +#include "secp256k1.h" + +// Set cp2 = cp1 +void point_copy(const curve_point* cp1, curve_point* cp2) { + *cp2 = *cp1; +} + +// cp2 = cp1 + cp2 +void point_add(const ecdsa_curve* curve, const curve_point* cp1, curve_point* cp2) { + bignum256 lambda = {0}, inv = {0}, xr = {0}, yr = {0}; + + if(point_is_infinity(cp1)) { + return; + } + if(point_is_infinity(cp2)) { + point_copy(cp1, cp2); + return; + } + if(point_is_equal(cp1, cp2)) { + point_double(curve, cp2); + return; + } + if(point_is_negative_of(cp1, cp2)) { + point_set_infinity(cp2); + return; + } + + // lambda = (y2 - y1) / (x2 - x1) + bn_subtractmod(&(cp2->x), &(cp1->x), &inv, &curve->prime); + bn_inverse(&inv, &curve->prime); + bn_subtractmod(&(cp2->y), &(cp1->y), &lambda, &curve->prime); + bn_multiply(&inv, &lambda, &curve->prime); + + // xr = lambda^2 - x1 - x2 + xr = lambda; + bn_multiply(&xr, &xr, &curve->prime); + yr = cp1->x; + bn_addmod(&yr, &(cp2->x), &curve->prime); + bn_subtractmod(&xr, &yr, &xr, &curve->prime); + bn_fast_mod(&xr, &curve->prime); + bn_mod(&xr, &curve->prime); + + // yr = lambda (x1 - xr) - y1 + bn_subtractmod(&(cp1->x), &xr, &yr, &curve->prime); + bn_multiply(&lambda, &yr, &curve->prime); + bn_subtractmod(&yr, &(cp1->y), &yr, &curve->prime); + bn_fast_mod(&yr, &curve->prime); + bn_mod(&yr, &curve->prime); + + cp2->x = xr; + cp2->y = yr; +} + +// cp = cp + cp +void point_double(const ecdsa_curve* curve, curve_point* cp) { + bignum256 lambda = {0}, xr = {0}, yr = {0}; + + if(point_is_infinity(cp)) { + return; + } + if(bn_is_zero(&(cp->y))) { + point_set_infinity(cp); + return; + } + + // lambda = (3 x^2 + a) / (2 y) + lambda = cp->y; + bn_mult_k(&lambda, 2, &curve->prime); + bn_fast_mod(&lambda, &curve->prime); + bn_mod(&lambda, &curve->prime); + bn_inverse(&lambda, &curve->prime); + + xr = cp->x; + bn_multiply(&xr, &xr, &curve->prime); + bn_mult_k(&xr, 3, &curve->prime); + bn_subi(&xr, -curve->a, &curve->prime); + bn_multiply(&xr, &lambda, &curve->prime); + + // xr = lambda^2 - 2*x + xr = lambda; + bn_multiply(&xr, &xr, &curve->prime); + yr = cp->x; + bn_lshift(&yr); + bn_subtractmod(&xr, &yr, &xr, &curve->prime); + bn_fast_mod(&xr, &curve->prime); + bn_mod(&xr, &curve->prime); + + // yr = lambda (x - xr) - y + bn_subtractmod(&(cp->x), &xr, &yr, &curve->prime); + bn_multiply(&lambda, &yr, &curve->prime); + bn_subtractmod(&yr, &(cp->y), &yr, &curve->prime); + bn_fast_mod(&yr, &curve->prime); + bn_mod(&yr, &curve->prime); + + cp->x = xr; + cp->y = yr; +} + +// set point to internal representation of point at infinity +void point_set_infinity(curve_point* p) { + bn_zero(&(p->x)); + bn_zero(&(p->y)); +} + +// return true iff p represent point at infinity +// both coords are zero in internal representation +int point_is_infinity(const curve_point* p) { + return bn_is_zero(&(p->x)) && bn_is_zero(&(p->y)); +} + +// return true iff both points are equal +int point_is_equal(const curve_point* p, const curve_point* q) { + return bn_is_equal(&(p->x), &(q->x)) && bn_is_equal(&(p->y), &(q->y)); +} + +// returns true iff p == -q +// expects p and q be valid points on curve other than point at infinity +int point_is_negative_of(const curve_point* p, const curve_point* q) { + // if P == (x, y), then -P would be (x, -y) on this curve + if(!bn_is_equal(&(p->x), &(q->x))) { + return 0; + } + + // we shouldn't hit this for a valid point + if(bn_is_zero(&(p->y))) { + return 0; + } + + return !bn_is_equal(&(p->y), &(q->y)); +} + +typedef struct jacobian_curve_point { + bignum256 x, y, z; +} jacobian_curve_point; + +// generate random K for signing/side-channel noise +static void generate_k_random(bignum256* k, const bignum256* prime) { + do { + int i = 0; + for(i = 0; i < 8; i++) { + k->val[i] = random32() & ((1u << BN_BITS_PER_LIMB) - 1); + } + k->val[8] = random32() & ((1u << BN_BITS_LAST_LIMB) - 1); + // check that k is in range and not zero. + } while(bn_is_zero(k) || !bn_is_less(k, prime)); +} + +void curve_to_jacobian(const curve_point* p, jacobian_curve_point* jp, const bignum256* prime) { + // randomize z coordinate + generate_k_random(&jp->z, prime); + + jp->x = jp->z; + bn_multiply(&jp->z, &jp->x, prime); + // x = z^2 + jp->y = jp->x; + bn_multiply(&jp->z, &jp->y, prime); + // y = z^3 + + bn_multiply(&p->x, &jp->x, prime); + bn_multiply(&p->y, &jp->y, prime); +} + +void jacobian_to_curve(const jacobian_curve_point* jp, curve_point* p, const bignum256* prime) { + p->y = jp->z; + bn_inverse(&p->y, prime); + // p->y = z^-1 + p->x = p->y; + bn_multiply(&p->x, &p->x, prime); + // p->x = z^-2 + bn_multiply(&p->x, &p->y, prime); + // p->y = z^-3 + bn_multiply(&jp->x, &p->x, prime); + // p->x = jp->x * z^-2 + bn_multiply(&jp->y, &p->y, prime); + // p->y = jp->y * z^-3 + bn_mod(&p->x, prime); + bn_mod(&p->y, prime); +} + +void point_jacobian_add(const curve_point* p1, jacobian_curve_point* p2, const ecdsa_curve* curve) { + bignum256 r = {0}, h = {0}, r2 = {0}; + bignum256 hcby = {0}, hsqx = {0}; + bignum256 xz = {0}, yz = {0}, az = {0}; + int is_doubling = 0; + const bignum256* prime = &curve->prime; + int a = curve->a; + + assert(-3 <= a && a <= 0); + + /* First we bring p1 to the same denominator: + * x1' := x1 * z2^2 + * y1' := y1 * z2^3 + */ + /* + * lambda = ((y1' - y2)/z2^3) / ((x1' - x2)/z2^2) + * = (y1' - y2) / (x1' - x2) z2 + * x3/z3^2 = lambda^2 - (x1' + x2)/z2^2 + * y3/z3^3 = 1/2 lambda * (2x3/z3^2 - (x1' + x2)/z2^2) + (y1'+y2)/z2^3 + * + * For the special case x1=x2, y1=y2 (doubling) we have + * lambda = 3/2 ((x2/z2^2)^2 + a) / (y2/z2^3) + * = 3/2 (x2^2 + a*z2^4) / y2*z2) + * + * to get rid of fraction we write lambda as + * lambda = r / (h*z2) + * with r = is_doubling ? 3/2 x2^2 + az2^4 : (y1 - y2) + * h = is_doubling ? y1+y2 : (x1 - x2) + * + * With z3 = h*z2 (the denominator of lambda) + * we get x3 = lambda^2*z3^2 - (x1' + x2)/z2^2*z3^2 + * = r^2 - h^2 * (x1' + x2) + * and y3 = 1/2 r * (2x3 - h^2*(x1' + x2)) + h^3*(y1' + y2) + */ + + /* h = x1 - x2 + * r = y1 - y2 + * x3 = r^2 - h^3 - 2*h^2*x2 + * y3 = r*(h^2*x2 - x3) - h^3*y2 + * z3 = h*z2 + */ + + xz = p2->z; + bn_multiply(&xz, &xz, prime); // xz = z2^2 + yz = p2->z; + bn_multiply(&xz, &yz, prime); // yz = z2^3 + + if(a != 0) { + az = xz; + bn_multiply(&az, &az, prime); // az = z2^4 + bn_mult_k(&az, -a, prime); // az = -az2^4 + } + + bn_multiply(&p1->x, &xz, prime); // xz = x1' = x1*z2^2; + h = xz; + bn_subtractmod(&h, &p2->x, &h, prime); + bn_fast_mod(&h, prime); + // h = x1' - x2; + + bn_add(&xz, &p2->x); + // xz = x1' + x2 + + // check for h == 0 % prime. Note that h never normalizes to + // zero, since h = x1' + 2*prime - x2 > 0 and a positive + // multiple of prime is always normalized to prime by + // bn_fast_mod. + is_doubling = bn_is_equal(&h, prime); + + bn_multiply(&p1->y, &yz, prime); // yz = y1' = y1*z2^3; + bn_subtractmod(&yz, &p2->y, &r, prime); + // r = y1' - y2; + + bn_add(&yz, &p2->y); + // yz = y1' + y2 + + r2 = p2->x; + bn_multiply(&r2, &r2, prime); + bn_mult_k(&r2, 3, prime); + + if(a != 0) { + // subtract -a z2^4, i.e, add a z2^4 + bn_subtractmod(&r2, &az, &r2, prime); + } + bn_cmov(&r, is_doubling, &r2, &r); + bn_cmov(&h, is_doubling, &yz, &h); + + // hsqx = h^2 + hsqx = h; + bn_multiply(&hsqx, &hsqx, prime); + + // hcby = h^3 + hcby = h; + bn_multiply(&hsqx, &hcby, prime); + + // hsqx = h^2 * (x1 + x2) + bn_multiply(&xz, &hsqx, prime); + + // hcby = h^3 * (y1 + y2) + bn_multiply(&yz, &hcby, prime); + + // z3 = h*z2 + bn_multiply(&h, &p2->z, prime); + + // x3 = r^2 - h^2 (x1 + x2) + p2->x = r; + bn_multiply(&p2->x, &p2->x, prime); + bn_subtractmod(&p2->x, &hsqx, &p2->x, prime); + bn_fast_mod(&p2->x, prime); + + // y3 = 1/2 (r*(h^2 (x1 + x2) - 2x3) - h^3 (y1 + y2)) + bn_subtractmod(&hsqx, &p2->x, &p2->y, prime); + bn_subtractmod(&p2->y, &p2->x, &p2->y, prime); + bn_multiply(&r, &p2->y, prime); + bn_subtractmod(&p2->y, &hcby, &p2->y, prime); + bn_mult_half(&p2->y, prime); + bn_fast_mod(&p2->y, prime); +} + +void point_jacobian_double(jacobian_curve_point* p, const ecdsa_curve* curve) { + bignum256 az4 = {0}, m = {0}, msq = {0}, ysq = {0}, xysq = {0}; + const bignum256* prime = &curve->prime; + + assert(-3 <= curve->a && curve->a <= 0); + /* usual algorithm: + * + * lambda = (3((x/z^2)^2 + a) / 2y/z^3) = (3x^2 + az^4)/2yz + * x3/z3^2 = lambda^2 - 2x/z^2 + * y3/z3^3 = lambda * (x/z^2 - x3/z3^2) - y/z^3 + * + * to get rid of fraction we set + * m = (3 x^2 + az^4) / 2 + * Hence, + * lambda = m / yz = m / z3 + * + * With z3 = yz (the denominator of lambda) + * we get x3 = lambda^2*z3^2 - 2*x/z^2*z3^2 + * = m^2 - 2*xy^2 + * and y3 = (lambda * (x/z^2 - x3/z3^2) - y/z^3) * z3^3 + * = m * (xy^2 - x3) - y^4 + */ + + /* m = (3*x^2 + a z^4) / 2 + * x3 = m^2 - 2*xy^2 + * y3 = m*(xy^2 - x3) - 8y^4 + * z3 = y*z + */ + + m = p->x; + bn_multiply(&m, &m, prime); + bn_mult_k(&m, 3, prime); + + az4 = p->z; + bn_multiply(&az4, &az4, prime); + bn_multiply(&az4, &az4, prime); + bn_mult_k(&az4, -curve->a, prime); + bn_subtractmod(&m, &az4, &m, prime); + bn_mult_half(&m, prime); + + // msq = m^2 + msq = m; + bn_multiply(&msq, &msq, prime); + // ysq = y^2 + ysq = p->y; + bn_multiply(&ysq, &ysq, prime); + // xysq = xy^2 + xysq = p->x; + bn_multiply(&ysq, &xysq, prime); + + // z3 = yz + bn_multiply(&p->y, &p->z, prime); + + // x3 = m^2 - 2*xy^2 + p->x = xysq; + bn_lshift(&p->x); + bn_fast_mod(&p->x, prime); + bn_subtractmod(&msq, &p->x, &p->x, prime); + bn_fast_mod(&p->x, prime); + + // y3 = m*(xy^2 - x3) - y^4 + bn_subtractmod(&xysq, &p->x, &p->y, prime); + bn_multiply(&m, &p->y, prime); + bn_multiply(&ysq, &ysq, prime); + bn_subtractmod(&p->y, &ysq, &p->y, prime); + bn_fast_mod(&p->y, prime); +} + +// res = k * p +// returns 0 on success +int point_multiply( + const ecdsa_curve* curve, + const bignum256* k, + const curve_point* p, + curve_point* res) { + // this algorithm is loosely based on + // Katsuyuki Okeya and Tsuyoshi Takagi, The Width-w NAF Method Provides + // Small Memory and Fast Elliptic Scalar Multiplications Secure against + // Side Channel Attacks. + if(!bn_is_less(k, &curve->order)) { + return 1; + } + + int i = 0, j = 0; + static CONFIDENTIAL bignum256 a; + uint32_t* aptr = NULL; + uint32_t abits = 0; + int ashift = 0; + uint32_t is_even = (k->val[0] & 1) - 1; + uint32_t bits = {0}, sign = {0}, nsign = {0}; + static CONFIDENTIAL jacobian_curve_point jres; + curve_point pmult[8] = {0}; + const bignum256* prime = &curve->prime; + + // is_even = 0xffffffff if k is even, 0 otherwise. + + // add 2^256. + // make number odd: subtract curve->order if even + uint32_t tmp = 1; + uint32_t is_non_zero = 0; + for(j = 0; j < 8; j++) { + is_non_zero |= k->val[j]; + tmp += (BN_BASE - 1) + k->val[j] - (curve->order.val[j] & is_even); + a.val[j] = tmp & (BN_BASE - 1); + tmp >>= BN_BITS_PER_LIMB; + } + is_non_zero |= k->val[j]; + a.val[j] = tmp + 0xffffff + k->val[j] - (curve->order.val[j] & is_even); + assert((a.val[0] & 1) != 0); + + // special case 0*p: just return zero. We don't care about constant time. + if(!is_non_zero) { + point_set_infinity(res); + return 1; + } + + // Now a = k + 2^256 (mod curve->order) and a is odd. + // + // The idea is to bring the new a into the form. + // sum_{i=0..64} a[i] 16^i, where |a[i]| < 16 and a[i] is odd. + // a[0] is odd, since a is odd. If a[i] would be even, we can + // add 1 to it and subtract 16 from a[i-1]. Afterwards, + // a[64] = 1, which is the 2^256 that we added before. + // + // Since k = a - 2^256 (mod curve->order), we can compute + // k*p = sum_{i=0..63} a[i] 16^i * p + // + // We compute |a[i]| * p in advance for all possible + // values of |a[i]| * p. pmult[i] = (2*i+1) * p + // We compute p, 3*p, ..., 15*p and store it in the table pmult. + // store p^2 temporarily in pmult[7] + pmult[7] = *p; + point_double(curve, &pmult[7]); + // compute 3*p, etc by repeatedly adding p^2. + pmult[0] = *p; + for(i = 1; i < 8; i++) { + pmult[i] = pmult[7]; + point_add(curve, &pmult[i - 1], &pmult[i]); + } + + // now compute res = sum_{i=0..63} a[i] * 16^i * p step by step, + // starting with i = 63. + // initialize jres = |a[63]| * p. + // Note that a[i] = a>>(4*i) & 0xf if (a&0x10) != 0 + // and - (16 - (a>>(4*i) & 0xf)) otherwise. We can compute this as + // ((a ^ (((a >> 4) & 1) - 1)) & 0xf) >> 1 + // since a is odd. + aptr = &a.val[8]; + abits = *aptr; + ashift = 256 - (BN_BITS_PER_LIMB * 8) - 4; + bits = abits >> ashift; + sign = (bits >> 4) - 1; + bits ^= sign; + bits &= 15; + curve_to_jacobian(&pmult[bits >> 1], &jres, prime); + for(i = 62; i >= 0; i--) { + // sign = sign(a[i+1]) (0xffffffff for negative, 0 for positive) + // invariant jres = (-1)^sign sum_{j=i+1..63} (a[j] * 16^{j-i-1} * p) + // abits >> (ashift - 4) = lowbits(a >> (i*4)) + + point_jacobian_double(&jres, curve); + point_jacobian_double(&jres, curve); + point_jacobian_double(&jres, curve); + point_jacobian_double(&jres, curve); + + // get lowest 5 bits of a >> (i*4). + ashift -= 4; + if(ashift < 0) { + // the condition only depends on the iteration number and + // leaks no private information to a side-channel. + bits = abits << (-ashift); + abits = *(--aptr); + ashift += BN_BITS_PER_LIMB; + bits |= abits >> ashift; + } else { + bits = abits >> ashift; + } + bits &= 31; + nsign = (bits >> 4) - 1; + bits ^= nsign; + bits &= 15; + + // negate last result to make signs of this round and the + // last round equal. + bn_cnegate((sign ^ nsign) & 1, &jres.z, prime); + + // add odd factor + point_jacobian_add(&pmult[bits >> 1], &jres, curve); + sign = nsign; + } + bn_cnegate(sign & 1, &jres.z, prime); + jacobian_to_curve(&jres, res, prime); + memzero(&a, sizeof(a)); + memzero(&jres, sizeof(jres)); + + return 0; +} + +#if USE_PRECOMPUTED_CP + +// res = k * G +// k must be a normalized number with 0 <= k < curve->order +// returns 0 on success +int scalar_multiply(const ecdsa_curve* curve, const bignum256* k, curve_point* res) { + if(!bn_is_less(k, &curve->order)) { + return 1; + } + + int i = {0}, j = {0}; + static CONFIDENTIAL bignum256 a; + uint32_t is_even = (k->val[0] & 1) - 1; + uint32_t lowbits = 0; + static CONFIDENTIAL jacobian_curve_point jres; + const bignum256* prime = &curve->prime; + + // is_even = 0xffffffff if k is even, 0 otherwise. + + // add 2^256. + // make number odd: subtract curve->order if even + uint32_t tmp = 1; + uint32_t is_non_zero = 0; + for(j = 0; j < 8; j++) { + is_non_zero |= k->val[j]; + tmp += (BN_BASE - 1) + k->val[j] - (curve->order.val[j] & is_even); + a.val[j] = tmp & (BN_BASE - 1); + tmp >>= BN_BITS_PER_LIMB; + } + is_non_zero |= k->val[j]; + a.val[j] = tmp + 0xffffff + k->val[j] - (curve->order.val[j] & is_even); + assert((a.val[0] & 1) != 0); + + // special case 0*G: just return zero. We don't care about constant time. + if(!is_non_zero) { + point_set_infinity(res); + return 0; + } + + // Now a = k + 2^256 (mod curve->order) and a is odd. + // + // The idea is to bring the new a into the form. + // sum_{i=0..64} a[i] 16^i, where |a[i]| < 16 and a[i] is odd. + // a[0] is odd, since a is odd. If a[i] would be even, we can + // add 1 to it and subtract 16 from a[i-1]. Afterwards, + // a[64] = 1, which is the 2^256 that we added before. + // + // Since k = a - 2^256 (mod curve->order), we can compute + // k*G = sum_{i=0..63} a[i] 16^i * G + // + // We have a big table curve->cp that stores all possible + // values of |a[i]| 16^i * G. + // curve->cp[i][j] = (2*j+1) * 16^i * G + + // now compute res = sum_{i=0..63} a[i] * 16^i * G step by step. + // initial res = |a[0]| * G. Note that a[0] = a & 0xf if (a&0x10) != 0 + // and - (16 - (a & 0xf)) otherwise. We can compute this as + // ((a ^ (((a >> 4) & 1) - 1)) & 0xf) >> 1 + // since a is odd. + lowbits = a.val[0] & ((1 << 5) - 1); + lowbits ^= (lowbits >> 4) - 1; + lowbits &= 15; + curve_to_jacobian(&curve->cp[0][lowbits >> 1], &jres, prime); + for(i = 1; i < 64; i++) { + // invariant res = sign(a[i-1]) sum_{j=0..i-1} (a[j] * 16^j * G) + + // shift a by 4 places. + for(j = 0; j < 8; j++) { + a.val[j] = (a.val[j] >> 4) | ((a.val[j + 1] & 0xf) << (BN_BITS_PER_LIMB - 4)); + } + a.val[j] >>= 4; + // a = old(a)>>(4*i) + // a is even iff sign(a[i-1]) = -1 + + lowbits = a.val[0] & ((1 << 5) - 1); + lowbits ^= (lowbits >> 4) - 1; + lowbits &= 15; + // negate last result to make signs of this round and the + // last round equal. + bn_cnegate(~lowbits & 1, &jres.y, prime); + + // add odd factor + point_jacobian_add(&curve->cp[i][lowbits >> 1], &jres, curve); + } + bn_cnegate(~(a.val[0] >> 4) & 1, &jres.y, prime); + jacobian_to_curve(&jres, res, prime); + memzero(&a, sizeof(a)); + memzero(&jres, sizeof(jres)); + + return 0; +} + +#else + +int scalar_multiply(const ecdsa_curve* curve, const bignum256* k, curve_point* res) { + return point_multiply(curve, k, &curve->G, res); +} + +#endif + +int ecdh_multiply( + const ecdsa_curve* curve, + const uint8_t* priv_key, + const uint8_t* pub_key, + uint8_t* session_key) { + curve_point point = {0}; + if(!ecdsa_read_pubkey(curve, pub_key, &point)) { + return 1; + } + + bignum256 k = {0}; + bn_read_be(priv_key, &k); + if(bn_is_zero(&k) || !bn_is_less(&k, &curve->order)) { + // Invalid private key. + return 2; + } + + point_multiply(curve, &k, &point, &point); + memzero(&k, sizeof(k)); + + session_key[0] = 0x04; + bn_write_be(&point.x, session_key + 1); + bn_write_be(&point.y, session_key + 33); + memzero(&point, sizeof(point)); + + return 0; +} + +// msg is a data to be signed +// msg_len is the message length +int ecdsa_sign( + const ecdsa_curve* curve, + HasherType hasher_sign, + const uint8_t* priv_key, + const uint8_t* msg, + uint32_t msg_len, + uint8_t* sig, + uint8_t* pby, + int (*is_canonical)(uint8_t by, uint8_t sig[64])) { + uint8_t hash[32] = {0}; + hasher_Raw(hasher_sign, msg, msg_len, hash); + int res = ecdsa_sign_digest(curve, priv_key, hash, sig, pby, is_canonical); + memzero(hash, sizeof(hash)); + return res; +} + +// uses secp256k1 curve +// priv_key is a 32 byte big endian stored number +// sig is 64 bytes long array for the signature +// digest is 32 bytes of digest +// is_canonical is an optional function that checks if the signature +// conforms to additional coin-specific rules. +int ecdsa_sign_digest( + const ecdsa_curve* curve, + const uint8_t* priv_key, + const uint8_t* digest, + uint8_t* sig, + uint8_t* pby, + int (*is_canonical)(uint8_t by, uint8_t sig[64])) { + int i = 0; + curve_point R = {0}; + bignum256 k = {0}, z = {0}, randk = {0}; + bignum256* s = &R.y; + uint8_t by; // signature recovery byte + +#if USE_RFC6979 + rfc6979_state rng = {0}; + init_rfc6979(priv_key, digest, curve, &rng); +#endif + + bn_read_be(digest, &z); + if(bn_is_zero(&z)) { + // The probability of the digest being all-zero by chance is infinitesimal, + // so this is most likely an indication of a bug. Furthermore, the signature + // has no value, because in this case it can be easily forged for any public + // key, see ecdsa_verify_digest(). + return 1; + } + + for(i = 0; i < 10000; i++) { +#if USE_RFC6979 + // generate K deterministically + generate_k_rfc6979(&k, &rng); + // if k is too big or too small, we don't like it + if(bn_is_zero(&k) || !bn_is_less(&k, &curve->order)) { + continue; + } +#else + // generate random number k + generate_k_random(&k, &curve->order); +#endif + + // compute k*G + scalar_multiply(curve, &k, &R); + by = R.y.val[0] & 1; + // r = (rx mod n) + if(!bn_is_less(&R.x, &curve->order)) { + bn_subtract(&R.x, &curve->order, &R.x); + by |= 2; + } + // if r is zero, we retry + if(bn_is_zero(&R.x)) { + continue; + } + + bn_read_be(priv_key, s); + if(bn_is_zero(s) || !bn_is_less(s, &curve->order)) { + // Invalid private key. + return 2; + } + + // randomize operations to counter side-channel attacks + generate_k_random(&randk, &curve->order); + bn_multiply(&randk, &k, &curve->order); // k*rand + bn_inverse(&k, &curve->order); // (k*rand)^-1 + bn_multiply(&R.x, s, &curve->order); // R.x*priv + bn_add(s, &z); // R.x*priv + z + bn_multiply(&k, s, &curve->order); // (k*rand)^-1 (R.x*priv + z) + bn_multiply(&randk, s, &curve->order); // k^-1 (R.x*priv + z) + bn_mod(s, &curve->order); + // if s is zero, we retry + if(bn_is_zero(s)) { + continue; + } + + // if S > order/2 => S = -S + if(bn_is_less(&curve->order_half, s)) { + bn_subtract(&curve->order, s, s); + by ^= 1; + } + // we are done, R.x and s is the result signature + bn_write_be(&R.x, sig); + bn_write_be(s, sig + 32); + + // check if the signature is acceptable or retry + if(is_canonical && !is_canonical(by, sig)) { + continue; + } + + if(pby) { + *pby = by; + } + + memzero(&k, sizeof(k)); + memzero(&randk, sizeof(randk)); +#if USE_RFC6979 + memzero(&rng, sizeof(rng)); +#endif + return 0; + } + + // Too many retries without a valid signature + // -> fail with an error + memzero(&k, sizeof(k)); + memzero(&randk, sizeof(randk)); +#if USE_RFC6979 + memzero(&rng, sizeof(rng)); +#endif + return -1; +} + +// returns 0 on success +int ecdsa_get_public_key33(const ecdsa_curve* curve, const uint8_t* priv_key, uint8_t* pub_key) { + curve_point R = {0}; + bignum256 k = {0}; + + bn_read_be(priv_key, &k); + if(bn_is_zero(&k) || !bn_is_less(&k, &curve->order)) { + // Invalid private key. + memzero(pub_key, 33); + return -1; + } + + // compute k*G + if(scalar_multiply(curve, &k, &R) != 0) { + memzero(&k, sizeof(k)); + return 1; + } + pub_key[0] = 0x02 | (R.y.val[0] & 0x01); + bn_write_be(&R.x, pub_key + 1); + memzero(&R, sizeof(R)); + memzero(&k, sizeof(k)); + return 0; +} + +// returns 0 on success +int ecdsa_get_public_key65(const ecdsa_curve* curve, const uint8_t* priv_key, uint8_t* pub_key) { + curve_point R = {0}; + bignum256 k = {0}; + + bn_read_be(priv_key, &k); + if(bn_is_zero(&k) || !bn_is_less(&k, &curve->order)) { + // Invalid private key. + memzero(pub_key, 65); + return -1; + } + + // compute k*G + if(scalar_multiply(curve, &k, &R) != 0) { + memzero(&k, sizeof(k)); + return 1; + } + pub_key[0] = 0x04; + bn_write_be(&R.x, pub_key + 1); + bn_write_be(&R.y, pub_key + 33); + memzero(&R, sizeof(R)); + memzero(&k, sizeof(k)); + return 0; +} + +int ecdsa_uncompress_pubkey( + const ecdsa_curve* curve, + const uint8_t* pub_key, + uint8_t* uncompressed) { + curve_point pub = {0}; + + if(!ecdsa_read_pubkey(curve, pub_key, &pub)) { + return 0; + } + + uncompressed[0] = 4; + bn_write_be(&pub.x, uncompressed + 1); + bn_write_be(&pub.y, uncompressed + 33); + + return 1; +} + +void ecdsa_get_pubkeyhash(const uint8_t* pub_key, HasherType hasher_pubkey, uint8_t* pubkeyhash) { + uint8_t h[HASHER_DIGEST_LENGTH] = {0}; + if(pub_key[0] == 0x04) { // uncompressed format + hasher_Raw(hasher_pubkey, pub_key, 65, h); + } else if(pub_key[0] == 0x00) { // point at infinity + hasher_Raw(hasher_pubkey, pub_key, 1, h); + } else { // expecting compressed format + hasher_Raw(hasher_pubkey, pub_key, 33, h); + } + memcpy(pubkeyhash, h, 20); + memzero(h, sizeof(h)); +} + +void ecdsa_get_address_raw( + const uint8_t* pub_key, + uint32_t version, + HasherType hasher_pubkey, + uint8_t* addr_raw) { + size_t prefix_len = address_prefix_bytes_len(version); + address_write_prefix_bytes(version, addr_raw); + ecdsa_get_pubkeyhash(pub_key, hasher_pubkey, addr_raw + prefix_len); +} + +void ecdsa_get_address( + const uint8_t* pub_key, + uint32_t version, + HasherType hasher_pubkey, + HasherType hasher_base58, + char* addr, + int addrsize) { + uint8_t raw[MAX_ADDR_RAW_SIZE] = {0}; + size_t prefix_len = address_prefix_bytes_len(version); + ecdsa_get_address_raw(pub_key, version, hasher_pubkey, raw); + base58_encode_check(raw, 20 + prefix_len, hasher_base58, addr, addrsize); + // not as important to clear this one, but we might as well + memzero(raw, sizeof(raw)); +} + +void ecdsa_get_address_segwit_p2sh_raw( + const uint8_t* pub_key, + uint32_t version, + HasherType hasher_pubkey, + uint8_t* addr_raw) { + uint8_t buf[32 + 2] = {0}; + buf[0] = 0; // version byte + buf[1] = 20; // push 20 bytes + ecdsa_get_pubkeyhash(pub_key, hasher_pubkey, buf + 2); + size_t prefix_len = address_prefix_bytes_len(version); + address_write_prefix_bytes(version, addr_raw); + hasher_Raw(hasher_pubkey, buf, 22, addr_raw + prefix_len); +} + +void ecdsa_get_address_segwit_p2sh( + const uint8_t* pub_key, + uint32_t version, + HasherType hasher_pubkey, + HasherType hasher_base58, + char* addr, + int addrsize) { + uint8_t raw[MAX_ADDR_RAW_SIZE] = {0}; + size_t prefix_len = address_prefix_bytes_len(version); + ecdsa_get_address_segwit_p2sh_raw(pub_key, version, hasher_pubkey, raw); + base58_encode_check(raw, prefix_len + 20, hasher_base58, addr, addrsize); + memzero(raw, sizeof(raw)); +} + +void ecdsa_get_wif( + const uint8_t* priv_key, + uint32_t version, + HasherType hasher_base58, + char* wif, + int wifsize) { + uint8_t wif_raw[MAX_WIF_RAW_SIZE] = {0}; + size_t prefix_len = address_prefix_bytes_len(version); + address_write_prefix_bytes(version, wif_raw); + memcpy(wif_raw + prefix_len, priv_key, 32); + wif_raw[prefix_len + 32] = 0x01; + base58_encode_check(wif_raw, prefix_len + 32 + 1, hasher_base58, wif, wifsize); + // private keys running around our stack can cause trouble + memzero(wif_raw, sizeof(wif_raw)); +} + +int ecdsa_address_decode( + const char* addr, + uint32_t version, + HasherType hasher_base58, + uint8_t* out) { + if(!addr) return 0; + int prefix_len = address_prefix_bytes_len(version); + return base58_decode_check(addr, hasher_base58, out, 20 + prefix_len) == 20 + prefix_len && + address_check_prefix(out, version); +} + +void compress_coords(const curve_point* cp, uint8_t* compressed) { + compressed[0] = bn_is_odd(&cp->y) ? 0x03 : 0x02; + bn_write_be(&cp->x, compressed + 1); +} + +void uncompress_coords(const ecdsa_curve* curve, uint8_t odd, const bignum256* x, bignum256* y) { + // y^2 = x^3 + a*x + b + memcpy(y, x, sizeof(bignum256)); // y is x + bn_multiply(x, y, &curve->prime); // y is x^2 + bn_subi(y, -curve->a, &curve->prime); // y is x^2 + a + bn_multiply(x, y, &curve->prime); // y is x^3 + ax + bn_add(y, &curve->b); // y is x^3 + ax + b + bn_sqrt(y, &curve->prime); // y = sqrt(y) + if((odd & 0x01) != (y->val[0] & 1)) { + bn_subtract(&curve->prime, y, y); // y = -y + } +} + +int ecdsa_read_pubkey(const ecdsa_curve* curve, const uint8_t* pub_key, curve_point* pub) { + if(!curve) { + curve = &secp256k1; + } + if(pub_key[0] == 0x04) { + bn_read_be(pub_key + 1, &(pub->x)); + bn_read_be(pub_key + 33, &(pub->y)); + return ecdsa_validate_pubkey(curve, pub); + } + if(pub_key[0] == 0x02 || pub_key[0] == 0x03) { // compute missing y coords + bn_read_be(pub_key + 1, &(pub->x)); + uncompress_coords(curve, pub_key[0], &(pub->x), &(pub->y)); + return ecdsa_validate_pubkey(curve, pub); + } + // error + return 0; +} + +// Verifies that: +// - pub is not the point at infinity. +// - pub->x and pub->y are in range [0,p-1]. +// - pub is on the curve. +// We assume that all curves using this code have cofactor 1, so there is no +// need to verify that pub is a scalar multiple of G. +int ecdsa_validate_pubkey(const ecdsa_curve* curve, const curve_point* pub) { + bignum256 y_2 = {0}, x3_ax_b = {0}; + + if(point_is_infinity(pub)) { + return 0; + } + + if(!bn_is_less(&(pub->x), &curve->prime) || !bn_is_less(&(pub->y), &curve->prime)) { + return 0; + } + + memcpy(&y_2, &(pub->y), sizeof(bignum256)); + memcpy(&x3_ax_b, &(pub->x), sizeof(bignum256)); + + // y^2 + bn_multiply(&(pub->y), &y_2, &curve->prime); + bn_mod(&y_2, &curve->prime); + + // x^3 + ax + b + bn_multiply(&(pub->x), &x3_ax_b, &curve->prime); // x^2 + bn_subi(&x3_ax_b, -curve->a, &curve->prime); // x^2 + a + bn_multiply(&(pub->x), &x3_ax_b, &curve->prime); // x^3 + ax + bn_addmod(&x3_ax_b, &curve->b, &curve->prime); // x^3 + ax + b + bn_mod(&x3_ax_b, &curve->prime); + + if(!bn_is_equal(&x3_ax_b, &y_2)) { + return 0; + } + + return 1; +} + +// uses secp256k1 curve +// pub_key - 65 bytes uncompressed key +// signature - 64 bytes signature +// msg is a data that was signed +// msg_len is the message length + +int ecdsa_verify( + const ecdsa_curve* curve, + HasherType hasher_sign, + const uint8_t* pub_key, + const uint8_t* sig, + const uint8_t* msg, + uint32_t msg_len) { + uint8_t hash[32] = {0}; + hasher_Raw(hasher_sign, msg, msg_len, hash); + int res = ecdsa_verify_digest(curve, pub_key, sig, hash); + memzero(hash, sizeof(hash)); + return res; +} + +// Compute public key from signature and recovery id. +// returns 0 if the key is successfully recovered +int ecdsa_recover_pub_from_sig( + const ecdsa_curve* curve, + uint8_t* pub_key, + const uint8_t* sig, + const uint8_t* digest, + int recid) { + bignum256 r = {0}, s = {0}, e = {0}; + curve_point cp = {0}, cp2 = {0}; + + // read r and s + bn_read_be(sig, &r); + bn_read_be(sig + 32, &s); + if(!bn_is_less(&r, &curve->order) || bn_is_zero(&r)) { + return 1; + } + if(!bn_is_less(&s, &curve->order) || bn_is_zero(&s)) { + return 1; + } + // cp = R = k * G (k is secret nonce when signing) + memcpy(&cp.x, &r, sizeof(bignum256)); + if(recid & 2) { + bn_add(&cp.x, &curve->order); + if(!bn_is_less(&cp.x, &curve->prime)) { + return 1; + } + } + // compute y from x + uncompress_coords(curve, recid & 1, &cp.x, &cp.y); + if(!ecdsa_validate_pubkey(curve, &cp)) { + return 1; + } + // e = -digest + bn_read_be(digest, &e); + bn_mod(&e, &curve->order); + bn_subtract(&curve->order, &e, &e); + // r = r^-1 + bn_inverse(&r, &curve->order); + // e = -digest * r^-1 + bn_multiply(&r, &e, &curve->order); + bn_mod(&e, &curve->order); + // s = s * r^-1 + bn_multiply(&r, &s, &curve->order); + bn_mod(&s, &curve->order); + // cp = s * r^-1 * k * G + point_multiply(curve, &s, &cp, &cp); + // cp2 = -digest * r^-1 * G + scalar_multiply(curve, &e, &cp2); + // cp = (s * r^-1 * k - digest * r^-1) * G = Pub + point_add(curve, &cp2, &cp); + // The point at infinity is not considered to be a valid public key. + if(point_is_infinity(&cp)) { + return 1; + } + pub_key[0] = 0x04; + bn_write_be(&cp.x, pub_key + 1); + bn_write_be(&cp.y, pub_key + 33); + return 0; +} + +// returns 0 if verification succeeded +int ecdsa_verify_digest( + const ecdsa_curve* curve, + const uint8_t* pub_key, + const uint8_t* sig, + const uint8_t* digest) { + curve_point pub = {0}, res = {0}; + bignum256 r = {0}, s = {0}, z = {0}; + int result = 0; + + if(!ecdsa_read_pubkey(curve, pub_key, &pub)) { + result = 1; + } + + if(result == 0) { + bn_read_be(sig, &r); + bn_read_be(sig + 32, &s); + bn_read_be(digest, &z); + if(bn_is_zero(&r) || bn_is_zero(&s) || (!bn_is_less(&r, &curve->order)) || + (!bn_is_less(&s, &curve->order))) { + result = 2; + } + if(bn_is_zero(&z)) { + // The digest was all-zero. The probability of this happening by chance is + // infinitesimal, but it could be induced by a fault injection. In this + // case the signature (r,s) can be forged by taking r := (t * Q).x mod n + // and s := r * t^-1 mod n for any t in [1, n-1]. We fail verification, + // because there is no guarantee that the signature was created by the + // owner of the private key. + result = 3; + } + } + + if(result == 0) { + bn_inverse(&s, &curve->order); // s = s^-1 + bn_multiply(&s, &z, &curve->order); // z = z * s [u1 = z * s^-1 mod n] + bn_mod(&z, &curve->order); + } + + if(result == 0) { + bn_multiply(&r, &s, &curve->order); // s = r * s [u2 = r * s^-1 mod n] + bn_mod(&s, &curve->order); + scalar_multiply(curve, &z, &res); // res = z * G [= u1 * G] + point_multiply(curve, &s, &pub, &pub); // pub = s * pub [= u2 * Q] + point_add(curve, &pub, &res); // res = pub + res [R = u1 * G + u2 * Q] + if(point_is_infinity(&res)) { + // R == Infinity + result = 4; + } + } + + if(result == 0) { + bn_mod(&(res.x), &curve->order); + if(!bn_is_equal(&res.x, &r)) { + // R.x != r + // signature does not match + result = 5; + } + } + + memzero(&pub, sizeof(pub)); + memzero(&res, sizeof(res)); + memzero(&r, sizeof(r)); + memzero(&s, sizeof(s)); + memzero(&z, sizeof(z)); + + // all OK + return result; +} + +int ecdsa_sig_to_der(const uint8_t* sig, uint8_t* der) { + int i = 0; + uint8_t *p = der, *len = NULL, *len1 = NULL, *len2 = NULL; + *p = 0x30; + p++; // sequence + *p = 0x00; + len = p; + p++; // len(sequence) + + *p = 0x02; + p++; // integer + *p = 0x00; + len1 = p; + p++; // len(integer) + + // process R + i = 0; + while(i < 31 && sig[i] == 0) { + i++; + } // skip leading zeroes + if(sig[i] >= 0x80) { // put zero in output if MSB set + *p = 0x00; + p++; + *len1 = *len1 + 1; + } + while(i < 32) { // copy bytes to output + *p = sig[i]; + p++; + *len1 = *len1 + 1; + i++; + } + + *p = 0x02; + p++; // integer + *p = 0x00; + len2 = p; + p++; // len(integer) + + // process S + i = 32; + while(i < 63 && sig[i] == 0) { + i++; + } // skip leading zeroes + if(sig[i] >= 0x80) { // put zero in output if MSB set + *p = 0x00; + p++; + *len2 = *len2 + 1; + } + while(i < 64) { // copy bytes to output + *p = sig[i]; + p++; + *len2 = *len2 + 1; + i++; + } + + *len = *len1 + *len2 + 4; + return *len + 2; +} + +// Parse a DER-encoded signature. We don't check whether the encoded integers +// satisfy DER requirements regarding leading zeros. +int ecdsa_sig_from_der(const uint8_t* der, size_t der_len, uint8_t sig[64]) { + memzero(sig, 64); + + // Check sequence header. + if(der_len < 2 || der_len > 72 || der[0] != 0x30 || der[1] != der_len - 2) { + return 1; + } + + // Read two DER-encoded integers. + size_t pos = 2; + for(int i = 0; i < 2; ++i) { + // Check integer header. + if(der_len < pos + 2 || der[pos] != 0x02) { + return 1; + } + + // Locate the integer. + size_t int_len = der[pos + 1]; + pos += 2; + if(pos + int_len > der_len) { + return 1; + } + + // Skip a possible leading zero. + if(int_len != 0 && der[pos] == 0) { + int_len--; + pos++; + } + + // Copy the integer to the output, making sure it fits. + if(int_len > 32) { + return 1; + } + memcpy(sig + 32 * (i + 1) - int_len, der + pos, int_len); + + // Move on to the next one. + pos += int_len; + } + + // Check that there are no trailing elements in the sequence. + if(pos != der_len) { + return 1; + } + + return 0; +} diff --git a/applications/external/flipbip/lib/crypto/ecdsa.h b/applications/external/flipbip/lib/crypto/ecdsa.h new file mode 100644 index 000000000..26192aa08 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/ecdsa.h @@ -0,0 +1,167 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __ECDSA_H__ +#define __ECDSA_H__ + +#include +#include "bignum.h" +#include "hasher.h" +#include "options.h" + +// curve point x and y +typedef struct { + bignum256 x, y; +} curve_point; + +typedef struct { + bignum256 prime; // prime order of the finite field + curve_point G; // initial curve point + bignum256 order; // order of G + bignum256 order_half; // order of G divided by 2 + int a; // coefficient 'a' of the elliptic curve + bignum256 b; // coefficient 'b' of the elliptic curve + +#if USE_PRECOMPUTED_CP + const curve_point cp[64][8]; +#endif + +} ecdsa_curve; + +// 4 byte prefix + 40 byte data (segwit) +// 1 byte prefix + 64 byte data (cashaddr) +#define MAX_ADDR_RAW_SIZE 65 +// bottle neck is cashaddr +// segwit is at most 90 characters plus NUL separator +// cashaddr: human readable prefix + 1 separator + 104 data + 8 checksum + 1 NUL +// we choose 130 as maximum (including NUL character) +#define MAX_ADDR_SIZE 130 +// 4 byte prefix + 32 byte privkey + 1 byte compressed marker +#define MAX_WIF_RAW_SIZE (4 + 32 + 1) +// (4 + 32 + 1 + 4 [checksum]) * 8 / log2(58) plus NUL. +#define MAX_WIF_SIZE (57) + +void point_copy(const curve_point* cp1, curve_point* cp2); +void point_add(const ecdsa_curve* curve, const curve_point* cp1, curve_point* cp2); +void point_double(const ecdsa_curve* curve, curve_point* cp); +int point_multiply( + const ecdsa_curve* curve, + const bignum256* k, + const curve_point* p, + curve_point* res); +void point_set_infinity(curve_point* p); +int point_is_infinity(const curve_point* p); +int point_is_equal(const curve_point* p, const curve_point* q); +int point_is_negative_of(const curve_point* p, const curve_point* q); +int scalar_multiply(const ecdsa_curve* curve, const bignum256* k, curve_point* res); +int ecdh_multiply( + const ecdsa_curve* curve, + const uint8_t* priv_key, + const uint8_t* pub_key, + uint8_t* session_key); +void compress_coords(const curve_point* cp, uint8_t* compressed); +void uncompress_coords(const ecdsa_curve* curve, uint8_t odd, const bignum256* x, bignum256* y); +int ecdsa_uncompress_pubkey( + const ecdsa_curve* curve, + const uint8_t* pub_key, + uint8_t* uncompressed); + +int ecdsa_sign( + const ecdsa_curve* curve, + HasherType hasher_sign, + const uint8_t* priv_key, + const uint8_t* msg, + uint32_t msg_len, + uint8_t* sig, + uint8_t* pby, + int (*is_canonical)(uint8_t by, uint8_t sig[64])); +int ecdsa_sign_digest( + const ecdsa_curve* curve, + const uint8_t* priv_key, + const uint8_t* digest, + uint8_t* sig, + uint8_t* pby, + int (*is_canonical)(uint8_t by, uint8_t sig[64])); +int ecdsa_get_public_key33(const ecdsa_curve* curve, const uint8_t* priv_key, uint8_t* pub_key); +int ecdsa_get_public_key65(const ecdsa_curve* curve, const uint8_t* priv_key, uint8_t* pub_key); +void ecdsa_get_pubkeyhash(const uint8_t* pub_key, HasherType hasher_pubkey, uint8_t* pubkeyhash); +void ecdsa_get_address_raw( + const uint8_t* pub_key, + uint32_t version, + HasherType hasher_pubkey, + uint8_t* addr_raw); +void ecdsa_get_address( + const uint8_t* pub_key, + uint32_t version, + HasherType hasher_pubkey, + HasherType hasher_base58, + char* addr, + int addrsize); +void ecdsa_get_address_segwit_p2sh_raw( + const uint8_t* pub_key, + uint32_t version, + HasherType hasher_pubkey, + uint8_t* addr_raw); +void ecdsa_get_address_segwit_p2sh( + const uint8_t* pub_key, + uint32_t version, + HasherType hasher_pubkey, + HasherType hasher_base58, + char* addr, + int addrsize); +void ecdsa_get_wif( + const uint8_t* priv_key, + uint32_t version, + HasherType hasher_base58, + char* wif, + int wifsize); + +int ecdsa_address_decode( + const char* addr, + uint32_t version, + HasherType hasher_base58, + uint8_t* out); +int ecdsa_read_pubkey(const ecdsa_curve* curve, const uint8_t* pub_key, curve_point* pub); +int ecdsa_validate_pubkey(const ecdsa_curve* curve, const curve_point* pub); +int ecdsa_verify( + const ecdsa_curve* curve, + HasherType hasher_sign, + const uint8_t* pub_key, + const uint8_t* sig, + const uint8_t* msg, + uint32_t msg_len); +int ecdsa_verify_digest( + const ecdsa_curve* curve, + const uint8_t* pub_key, + const uint8_t* sig, + const uint8_t* digest); +int ecdsa_recover_pub_from_sig( + const ecdsa_curve* curve, + uint8_t* pub_key, + const uint8_t* sig, + const uint8_t* digest, + int recid); +int ecdsa_sig_to_der(const uint8_t* sig, uint8_t* der); +int ecdsa_sig_from_der(const uint8_t* der, size_t der_len, uint8_t sig[64]); + +#endif diff --git a/applications/external/flipbip/lib/crypto/ed25519_donna/curve25519_donna_32bit.c b/applications/external/flipbip/lib/crypto/ed25519_donna/curve25519_donna_32bit.c new file mode 100644 index 000000000..603abeb24 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/ed25519_donna/curve25519_donna_32bit.c @@ -0,0 +1,953 @@ +/* + Public domain by Andrew M. + See: https://github.com/floodyberry/curve25519-donna + + 32 bit integer curve25519 implementation +*/ + +#include "ed25519_donna.h" + +static const uint32_t reduce_mask_25 = (1 << 25) - 1; +static const uint32_t reduce_mask_26 = (1 << 26) - 1; + +/* out = in */ +void curve25519_copy(bignum25519 out, const bignum25519 in) { + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; + out[3] = in[3]; + out[4] = in[4]; + out[5] = in[5]; + out[6] = in[6]; + out[7] = in[7]; + out[8] = in[8]; + out[9] = in[9]; +} + +/* out = a + b */ +void curve25519_add(bignum25519 out, const bignum25519 a, const bignum25519 b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + out[3] = a[3] + b[3]; + out[4] = a[4] + b[4]; + out[5] = a[5] + b[5]; + out[6] = a[6] + b[6]; + out[7] = a[7] + b[7]; + out[8] = a[8] + b[8]; + out[9] = a[9] + b[9]; +} + +void curve25519_add_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b) { + uint32_t c = 0; + out[0] = a[0] + b[0]; + c = (out[0] >> 26); + out[0] &= reduce_mask_26; + out[1] = a[1] + b[1] + c; + c = (out[1] >> 25); + out[1] &= reduce_mask_25; + out[2] = a[2] + b[2] + c; + c = (out[2] >> 26); + out[2] &= reduce_mask_26; + out[3] = a[3] + b[3] + c; + c = (out[3] >> 25); + out[3] &= reduce_mask_25; + out[4] = a[4] + b[4] + c; + c = (out[4] >> 26); + out[4] &= reduce_mask_26; + out[5] = a[5] + b[5] + c; + c = (out[5] >> 25); + out[5] &= reduce_mask_25; + out[6] = a[6] + b[6] + c; + c = (out[6] >> 26); + out[6] &= reduce_mask_26; + out[7] = a[7] + b[7] + c; + c = (out[7] >> 25); + out[7] &= reduce_mask_25; + out[8] = a[8] + b[8] + c; + c = (out[8] >> 26); + out[8] &= reduce_mask_26; + out[9] = a[9] + b[9] + c; + c = (out[9] >> 25); + out[9] &= reduce_mask_25; + out[0] += 19 * c; +} + +void curve25519_add_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b) { + uint32_t c = 0; + out[0] = a[0] + b[0]; + c = (out[0] >> 26); + out[0] &= reduce_mask_26; + out[1] = a[1] + b[1] + c; + c = (out[1] >> 25); + out[1] &= reduce_mask_25; + out[2] = a[2] + b[2] + c; + c = (out[2] >> 26); + out[2] &= reduce_mask_26; + out[3] = a[3] + b[3] + c; + c = (out[3] >> 25); + out[3] &= reduce_mask_25; + out[4] = a[4] + b[4] + c; + c = (out[4] >> 26); + out[4] &= reduce_mask_26; + out[5] = a[5] + b[5] + c; + c = (out[5] >> 25); + out[5] &= reduce_mask_25; + out[6] = a[6] + b[6] + c; + c = (out[6] >> 26); + out[6] &= reduce_mask_26; + out[7] = a[7] + b[7] + c; + c = (out[7] >> 25); + out[7] &= reduce_mask_25; + out[8] = a[8] + b[8] + c; + c = (out[8] >> 26); + out[8] &= reduce_mask_26; + out[9] = a[9] + b[9] + c; + c = (out[9] >> 25); + out[9] &= reduce_mask_25; + out[0] += 19 * c; +} + +/* multiples of p */ +static const uint32_t twoP0 = 0x07ffffda; +static const uint32_t twoP13579 = 0x03fffffe; +static const uint32_t twoP2468 = 0x07fffffe; +static const uint32_t fourP0 = 0x0fffffb4; +static const uint32_t fourP13579 = 0x07fffffc; +static const uint32_t fourP2468 = 0x0ffffffc; + +/* out = a - b */ +void curve25519_sub(bignum25519 out, const bignum25519 a, const bignum25519 b) { + uint32_t c = 0; + out[0] = twoP0 + a[0] - b[0]; + c = (out[0] >> 26); + out[0] &= reduce_mask_26; + out[1] = twoP13579 + a[1] - b[1] + c; + c = (out[1] >> 25); + out[1] &= reduce_mask_25; + out[2] = twoP2468 + a[2] - b[2] + c; + c = (out[2] >> 26); + out[2] &= reduce_mask_26; + out[3] = twoP13579 + a[3] - b[3] + c; + c = (out[3] >> 25); + out[3] &= reduce_mask_25; + out[4] = twoP2468 + a[4] - b[4] + c; + out[5] = twoP13579 + a[5] - b[5]; + out[6] = twoP2468 + a[6] - b[6]; + out[7] = twoP13579 + a[7] - b[7]; + out[8] = twoP2468 + a[8] - b[8]; + out[9] = twoP13579 + a[9] - b[9]; +} + +/* out = in * scalar */ +void curve25519_scalar_product(bignum25519 out, const bignum25519 in, const uint32_t scalar) { + uint64_t a = 0; + uint32_t c = 0; + a = mul32x32_64(in[0], scalar); + out[0] = (uint32_t)a & reduce_mask_26; + c = (uint32_t)(a >> 26); + a = mul32x32_64(in[1], scalar) + c; + out[1] = (uint32_t)a & reduce_mask_25; + c = (uint32_t)(a >> 25); + a = mul32x32_64(in[2], scalar) + c; + out[2] = (uint32_t)a & reduce_mask_26; + c = (uint32_t)(a >> 26); + a = mul32x32_64(in[3], scalar) + c; + out[3] = (uint32_t)a & reduce_mask_25; + c = (uint32_t)(a >> 25); + a = mul32x32_64(in[4], scalar) + c; + out[4] = (uint32_t)a & reduce_mask_26; + c = (uint32_t)(a >> 26); + a = mul32x32_64(in[5], scalar) + c; + out[5] = (uint32_t)a & reduce_mask_25; + c = (uint32_t)(a >> 25); + a = mul32x32_64(in[6], scalar) + c; + out[6] = (uint32_t)a & reduce_mask_26; + c = (uint32_t)(a >> 26); + a = mul32x32_64(in[7], scalar) + c; + out[7] = (uint32_t)a & reduce_mask_25; + c = (uint32_t)(a >> 25); + a = mul32x32_64(in[8], scalar) + c; + out[8] = (uint32_t)a & reduce_mask_26; + c = (uint32_t)(a >> 26); + a = mul32x32_64(in[9], scalar) + c; + out[9] = (uint32_t)a & reduce_mask_25; + c = (uint32_t)(a >> 25); + out[0] += c * 19; +} + +/* out = a - b, where a is the result of a basic op (add,sub) */ +void curve25519_sub_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b) { + uint32_t c = 0; + out[0] = fourP0 + a[0] - b[0]; + c = (out[0] >> 26); + out[0] &= reduce_mask_26; + out[1] = fourP13579 + a[1] - b[1] + c; + c = (out[1] >> 25); + out[1] &= reduce_mask_25; + out[2] = fourP2468 + a[2] - b[2] + c; + c = (out[2] >> 26); + out[2] &= reduce_mask_26; + out[3] = fourP13579 + a[3] - b[3] + c; + c = (out[3] >> 25); + out[3] &= reduce_mask_25; + out[4] = fourP2468 + a[4] - b[4] + c; + c = (out[4] >> 26); + out[4] &= reduce_mask_26; + out[5] = fourP13579 + a[5] - b[5] + c; + c = (out[5] >> 25); + out[5] &= reduce_mask_25; + out[6] = fourP2468 + a[6] - b[6] + c; + c = (out[6] >> 26); + out[6] &= reduce_mask_26; + out[7] = fourP13579 + a[7] - b[7] + c; + c = (out[7] >> 25); + out[7] &= reduce_mask_25; + out[8] = fourP2468 + a[8] - b[8] + c; + c = (out[8] >> 26); + out[8] &= reduce_mask_26; + out[9] = fourP13579 + a[9] - b[9] + c; + c = (out[9] >> 25); + out[9] &= reduce_mask_25; + out[0] += 19 * c; +} + +void curve25519_sub_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b) { + uint32_t c = 0; + out[0] = fourP0 + a[0] - b[0]; + c = (out[0] >> 26); + out[0] &= reduce_mask_26; + out[1] = fourP13579 + a[1] - b[1] + c; + c = (out[1] >> 25); + out[1] &= reduce_mask_25; + out[2] = fourP2468 + a[2] - b[2] + c; + c = (out[2] >> 26); + out[2] &= reduce_mask_26; + out[3] = fourP13579 + a[3] - b[3] + c; + c = (out[3] >> 25); + out[3] &= reduce_mask_25; + out[4] = fourP2468 + a[4] - b[4] + c; + c = (out[4] >> 26); + out[4] &= reduce_mask_26; + out[5] = fourP13579 + a[5] - b[5] + c; + c = (out[5] >> 25); + out[5] &= reduce_mask_25; + out[6] = fourP2468 + a[6] - b[6] + c; + c = (out[6] >> 26); + out[6] &= reduce_mask_26; + out[7] = fourP13579 + a[7] - b[7] + c; + c = (out[7] >> 25); + out[7] &= reduce_mask_25; + out[8] = fourP2468 + a[8] - b[8] + c; + c = (out[8] >> 26); + out[8] &= reduce_mask_26; + out[9] = fourP13579 + a[9] - b[9] + c; + c = (out[9] >> 25); + out[9] &= reduce_mask_25; + out[0] += 19 * c; +} + +/* out = -a */ +void curve25519_neg(bignum25519 out, const bignum25519 a) { + uint32_t c = 0; + out[0] = twoP0 - a[0]; + c = (out[0] >> 26); + out[0] &= reduce_mask_26; + out[1] = twoP13579 - a[1] + c; + c = (out[1] >> 25); + out[1] &= reduce_mask_25; + out[2] = twoP2468 - a[2] + c; + c = (out[2] >> 26); + out[2] &= reduce_mask_26; + out[3] = twoP13579 - a[3] + c; + c = (out[3] >> 25); + out[3] &= reduce_mask_25; + out[4] = twoP2468 - a[4] + c; + c = (out[4] >> 26); + out[4] &= reduce_mask_26; + out[5] = twoP13579 - a[5] + c; + c = (out[5] >> 25); + out[5] &= reduce_mask_25; + out[6] = twoP2468 - a[6] + c; + c = (out[6] >> 26); + out[6] &= reduce_mask_26; + out[7] = twoP13579 - a[7] + c; + c = (out[7] >> 25); + out[7] &= reduce_mask_25; + out[8] = twoP2468 - a[8] + c; + c = (out[8] >> 26); + out[8] &= reduce_mask_26; + out[9] = twoP13579 - a[9] + c; + c = (out[9] >> 25); + out[9] &= reduce_mask_25; + out[0] += 19 * c; +} + +/* out = a * b */ +#define curve25519_mul_noinline curve25519_mul +void curve25519_mul(bignum25519 out, const bignum25519 a, const bignum25519 b) { + uint32_t r0 = 0, r1 = 0, r2 = 0, r3 = 0, r4 = 0, r5 = 0, r6 = 0, r7 = 0, r8 = 0, r9 = 0; + uint32_t s0 = 0, s1 = 0, s2 = 0, s3 = 0, s4 = 0, s5 = 0, s6 = 0, s7 = 0, s8 = 0, s9 = 0; + uint64_t m0 = 0, m1 = 0, m2 = 0, m3 = 0, m4 = 0, m5 = 0, m6 = 0, m7 = 0, m8 = 0, m9 = 0, c = 0; + uint32_t p = 0; + + r0 = b[0]; + r1 = b[1]; + r2 = b[2]; + r3 = b[3]; + r4 = b[4]; + r5 = b[5]; + r6 = b[6]; + r7 = b[7]; + r8 = b[8]; + r9 = b[9]; + + s0 = a[0]; + s1 = a[1]; + s2 = a[2]; + s3 = a[3]; + s4 = a[4]; + s5 = a[5]; + s6 = a[6]; + s7 = a[7]; + s8 = a[8]; + s9 = a[9]; + + m1 = mul32x32_64(r0, s1) + mul32x32_64(r1, s0); + m3 = mul32x32_64(r0, s3) + mul32x32_64(r1, s2) + mul32x32_64(r2, s1) + mul32x32_64(r3, s0); + m5 = mul32x32_64(r0, s5) + mul32x32_64(r1, s4) + mul32x32_64(r2, s3) + mul32x32_64(r3, s2) + + mul32x32_64(r4, s1) + mul32x32_64(r5, s0); + m7 = mul32x32_64(r0, s7) + mul32x32_64(r1, s6) + mul32x32_64(r2, s5) + mul32x32_64(r3, s4) + + mul32x32_64(r4, s3) + mul32x32_64(r5, s2) + mul32x32_64(r6, s1) + mul32x32_64(r7, s0); + m9 = mul32x32_64(r0, s9) + mul32x32_64(r1, s8) + mul32x32_64(r2, s7) + mul32x32_64(r3, s6) + + mul32x32_64(r4, s5) + mul32x32_64(r5, s4) + mul32x32_64(r6, s3) + mul32x32_64(r7, s2) + + mul32x32_64(r8, s1) + mul32x32_64(r9, s0); + + r1 *= 2; + r3 *= 2; + r5 *= 2; + r7 *= 2; + + m0 = mul32x32_64(r0, s0); + m2 = mul32x32_64(r0, s2) + mul32x32_64(r1, s1) + mul32x32_64(r2, s0); + m4 = mul32x32_64(r0, s4) + mul32x32_64(r1, s3) + mul32x32_64(r2, s2) + mul32x32_64(r3, s1) + + mul32x32_64(r4, s0); + m6 = mul32x32_64(r0, s6) + mul32x32_64(r1, s5) + mul32x32_64(r2, s4) + mul32x32_64(r3, s3) + + mul32x32_64(r4, s2) + mul32x32_64(r5, s1) + mul32x32_64(r6, s0); + m8 = mul32x32_64(r0, s8) + mul32x32_64(r1, s7) + mul32x32_64(r2, s6) + mul32x32_64(r3, s5) + + mul32x32_64(r4, s4) + mul32x32_64(r5, s3) + mul32x32_64(r6, s2) + mul32x32_64(r7, s1) + + mul32x32_64(r8, s0); + + r1 *= 19; + r2 *= 19; + r3 = (r3 / 2) * 19; + r4 *= 19; + r5 = (r5 / 2) * 19; + r6 *= 19; + r7 = (r7 / 2) * 19; + r8 *= 19; + r9 *= 19; + + m1 += + (mul32x32_64(r9, s2) + mul32x32_64(r8, s3) + mul32x32_64(r7, s4) + mul32x32_64(r6, s5) + + mul32x32_64(r5, s6) + mul32x32_64(r4, s7) + mul32x32_64(r3, s8) + mul32x32_64(r2, s9)); + m3 += + (mul32x32_64(r9, s4) + mul32x32_64(r8, s5) + mul32x32_64(r7, s6) + mul32x32_64(r6, s7) + + mul32x32_64(r5, s8) + mul32x32_64(r4, s9)); + m5 += (mul32x32_64(r9, s6) + mul32x32_64(r8, s7) + mul32x32_64(r7, s8) + mul32x32_64(r6, s9)); + m7 += (mul32x32_64(r9, s8) + mul32x32_64(r8, s9)); + + r3 *= 2; + r5 *= 2; + r7 *= 2; + r9 *= 2; + + m0 += + (mul32x32_64(r9, s1) + mul32x32_64(r8, s2) + mul32x32_64(r7, s3) + mul32x32_64(r6, s4) + + mul32x32_64(r5, s5) + mul32x32_64(r4, s6) + mul32x32_64(r3, s7) + mul32x32_64(r2, s8) + + mul32x32_64(r1, s9)); + m2 += + (mul32x32_64(r9, s3) + mul32x32_64(r8, s4) + mul32x32_64(r7, s5) + mul32x32_64(r6, s6) + + mul32x32_64(r5, s7) + mul32x32_64(r4, s8) + mul32x32_64(r3, s9)); + m4 += + (mul32x32_64(r9, s5) + mul32x32_64(r8, s6) + mul32x32_64(r7, s7) + mul32x32_64(r6, s8) + + mul32x32_64(r5, s9)); + m6 += (mul32x32_64(r9, s7) + mul32x32_64(r8, s8) + mul32x32_64(r7, s9)); + m8 += (mul32x32_64(r9, s9)); + + r0 = (uint32_t)m0 & reduce_mask_26; + c = (m0 >> 26); + m1 += c; + r1 = (uint32_t)m1 & reduce_mask_25; + c = (m1 >> 25); + m2 += c; + r2 = (uint32_t)m2 & reduce_mask_26; + c = (m2 >> 26); + m3 += c; + r3 = (uint32_t)m3 & reduce_mask_25; + c = (m3 >> 25); + m4 += c; + r4 = (uint32_t)m4 & reduce_mask_26; + c = (m4 >> 26); + m5 += c; + r5 = (uint32_t)m5 & reduce_mask_25; + c = (m5 >> 25); + m6 += c; + r6 = (uint32_t)m6 & reduce_mask_26; + c = (m6 >> 26); + m7 += c; + r7 = (uint32_t)m7 & reduce_mask_25; + c = (m7 >> 25); + m8 += c; + r8 = (uint32_t)m8 & reduce_mask_26; + c = (m8 >> 26); + m9 += c; + r9 = (uint32_t)m9 & reduce_mask_25; + p = (uint32_t)(m9 >> 25); + m0 = r0 + mul32x32_64(p, 19); + r0 = (uint32_t)m0 & reduce_mask_26; + p = (uint32_t)(m0 >> 26); + r1 += p; + + out[0] = r0; + out[1] = r1; + out[2] = r2; + out[3] = r3; + out[4] = r4; + out[5] = r5; + out[6] = r6; + out[7] = r7; + out[8] = r8; + out[9] = r9; +} + +/* out = in * in */ +void curve25519_square(bignum25519 out, const bignum25519 in) { + uint32_t r0 = 0, r1 = 0, r2 = 0, r3 = 0, r4 = 0, r5 = 0, r6 = 0, r7 = 0, r8 = 0, r9 = 0; + uint32_t d6 = 0, d7 = 0, d8 = 0, d9 = 0; + uint64_t m0 = 0, m1 = 0, m2 = 0, m3 = 0, m4 = 0, m5 = 0, m6 = 0, m7 = 0, m8 = 0, m9 = 0, c = 0; + uint32_t p = 0; + + r0 = in[0]; + r1 = in[1]; + r2 = in[2]; + r3 = in[3]; + r4 = in[4]; + r5 = in[5]; + r6 = in[6]; + r7 = in[7]; + r8 = in[8]; + r9 = in[9]; + + m0 = mul32x32_64(r0, r0); + r0 *= 2; + m1 = mul32x32_64(r0, r1); + m2 = mul32x32_64(r0, r2) + mul32x32_64(r1, r1 * 2); + r1 *= 2; + m3 = mul32x32_64(r0, r3) + mul32x32_64(r1, r2); + m4 = mul32x32_64(r0, r4) + mul32x32_64(r1, r3 * 2) + mul32x32_64(r2, r2); + r2 *= 2; + m5 = mul32x32_64(r0, r5) + mul32x32_64(r1, r4) + mul32x32_64(r2, r3); + m6 = mul32x32_64(r0, r6) + mul32x32_64(r1, r5 * 2) + mul32x32_64(r2, r4) + + mul32x32_64(r3, r3 * 2); + r3 *= 2; + m7 = mul32x32_64(r0, r7) + mul32x32_64(r1, r6) + mul32x32_64(r2, r5) + mul32x32_64(r3, r4); + m8 = mul32x32_64(r0, r8) + mul32x32_64(r1, r7 * 2) + mul32x32_64(r2, r6) + + mul32x32_64(r3, r5 * 2) + mul32x32_64(r4, r4); + m9 = mul32x32_64(r0, r9) + mul32x32_64(r1, r8) + mul32x32_64(r2, r7) + mul32x32_64(r3, r6) + + mul32x32_64(r4, r5 * 2); + + d6 = r6 * 19; + d7 = r7 * 2 * 19; + d8 = r8 * 19; + d9 = r9 * 2 * 19; + + m0 += + (mul32x32_64(d9, r1) + mul32x32_64(d8, r2) + mul32x32_64(d7, r3) + + mul32x32_64(d6, r4 * 2) + mul32x32_64(r5, r5 * 2 * 19)); + m1 += + (mul32x32_64(d9, r2 / 2) + mul32x32_64(d8, r3) + mul32x32_64(d7, r4) + + mul32x32_64(d6, r5 * 2)); + m2 += + (mul32x32_64(d9, r3) + mul32x32_64(d8, r4 * 2) + mul32x32_64(d7, r5 * 2) + + mul32x32_64(d6, r6)); + m3 += (mul32x32_64(d9, r4) + mul32x32_64(d8, r5 * 2) + mul32x32_64(d7, r6)); + m4 += (mul32x32_64(d9, r5 * 2) + mul32x32_64(d8, r6 * 2) + mul32x32_64(d7, r7)); + m5 += (mul32x32_64(d9, r6) + mul32x32_64(d8, r7 * 2)); + m6 += (mul32x32_64(d9, r7 * 2) + mul32x32_64(d8, r8)); + m7 += (mul32x32_64(d9, r8)); + m8 += (mul32x32_64(d9, r9)); + + r0 = (uint32_t)m0 & reduce_mask_26; + c = (m0 >> 26); + m1 += c; + r1 = (uint32_t)m1 & reduce_mask_25; + c = (m1 >> 25); + m2 += c; + r2 = (uint32_t)m2 & reduce_mask_26; + c = (m2 >> 26); + m3 += c; + r3 = (uint32_t)m3 & reduce_mask_25; + c = (m3 >> 25); + m4 += c; + r4 = (uint32_t)m4 & reduce_mask_26; + c = (m4 >> 26); + m5 += c; + r5 = (uint32_t)m5 & reduce_mask_25; + c = (m5 >> 25); + m6 += c; + r6 = (uint32_t)m6 & reduce_mask_26; + c = (m6 >> 26); + m7 += c; + r7 = (uint32_t)m7 & reduce_mask_25; + c = (m7 >> 25); + m8 += c; + r8 = (uint32_t)m8 & reduce_mask_26; + c = (m8 >> 26); + m9 += c; + r9 = (uint32_t)m9 & reduce_mask_25; + p = (uint32_t)(m9 >> 25); + m0 = r0 + mul32x32_64(p, 19); + r0 = (uint32_t)m0 & reduce_mask_26; + p = (uint32_t)(m0 >> 26); + r1 += p; + + out[0] = r0; + out[1] = r1; + out[2] = r2; + out[3] = r3; + out[4] = r4; + out[5] = r5; + out[6] = r6; + out[7] = r7; + out[8] = r8; + out[9] = r9; +} + +/* out = in ^ (2 * count) */ +void curve25519_square_times(bignum25519 out, const bignum25519 in, int count) { + uint32_t r0 = 0, r1 = 0, r2 = 0, r3 = 0, r4 = 0, r5 = 0, r6 = 0, r7 = 0, r8 = 0, r9 = 0; + uint32_t d6 = 0, d7 = 0, d8 = 0, d9 = 0; + uint64_t m0 = 0, m1 = 0, m2 = 0, m3 = 0, m4 = 0, m5 = 0, m6 = 0, m7 = 0, m8 = 0, m9 = 0, c = 0; + uint32_t p = 0; + + r0 = in[0]; + r1 = in[1]; + r2 = in[2]; + r3 = in[3]; + r4 = in[4]; + r5 = in[5]; + r6 = in[6]; + r7 = in[7]; + r8 = in[8]; + r9 = in[9]; + + do { + m0 = mul32x32_64(r0, r0); + r0 *= 2; + m1 = mul32x32_64(r0, r1); + m2 = mul32x32_64(r0, r2) + mul32x32_64(r1, r1 * 2); + r1 *= 2; + m3 = mul32x32_64(r0, r3) + mul32x32_64(r1, r2); + m4 = mul32x32_64(r0, r4) + mul32x32_64(r1, r3 * 2) + mul32x32_64(r2, r2); + r2 *= 2; + m5 = mul32x32_64(r0, r5) + mul32x32_64(r1, r4) + mul32x32_64(r2, r3); + m6 = mul32x32_64(r0, r6) + mul32x32_64(r1, r5 * 2) + mul32x32_64(r2, r4) + + mul32x32_64(r3, r3 * 2); + r3 *= 2; + m7 = mul32x32_64(r0, r7) + mul32x32_64(r1, r6) + mul32x32_64(r2, r5) + mul32x32_64(r3, r4); + m8 = mul32x32_64(r0, r8) + mul32x32_64(r1, r7 * 2) + mul32x32_64(r2, r6) + + mul32x32_64(r3, r5 * 2) + mul32x32_64(r4, r4); + m9 = mul32x32_64(r0, r9) + mul32x32_64(r1, r8) + mul32x32_64(r2, r7) + + mul32x32_64(r3, r6) + mul32x32_64(r4, r5 * 2); + + d6 = r6 * 19; + d7 = r7 * 2 * 19; + d8 = r8 * 19; + d9 = r9 * 2 * 19; + + m0 += + (mul32x32_64(d9, r1) + mul32x32_64(d8, r2) + mul32x32_64(d7, r3) + + mul32x32_64(d6, r4 * 2) + mul32x32_64(r5, r5 * 2 * 19)); + m1 += + (mul32x32_64(d9, r2 / 2) + mul32x32_64(d8, r3) + mul32x32_64(d7, r4) + + mul32x32_64(d6, r5 * 2)); + m2 += + (mul32x32_64(d9, r3) + mul32x32_64(d8, r4 * 2) + mul32x32_64(d7, r5 * 2) + + mul32x32_64(d6, r6)); + m3 += (mul32x32_64(d9, r4) + mul32x32_64(d8, r5 * 2) + mul32x32_64(d7, r6)); + m4 += (mul32x32_64(d9, r5 * 2) + mul32x32_64(d8, r6 * 2) + mul32x32_64(d7, r7)); + m5 += (mul32x32_64(d9, r6) + mul32x32_64(d8, r7 * 2)); + m6 += (mul32x32_64(d9, r7 * 2) + mul32x32_64(d8, r8)); + m7 += (mul32x32_64(d9, r8)); + m8 += (mul32x32_64(d9, r9)); + + r0 = (uint32_t)m0 & reduce_mask_26; + c = (m0 >> 26); + m1 += c; + r1 = (uint32_t)m1 & reduce_mask_25; + c = (m1 >> 25); + m2 += c; + r2 = (uint32_t)m2 & reduce_mask_26; + c = (m2 >> 26); + m3 += c; + r3 = (uint32_t)m3 & reduce_mask_25; + c = (m3 >> 25); + m4 += c; + r4 = (uint32_t)m4 & reduce_mask_26; + c = (m4 >> 26); + m5 += c; + r5 = (uint32_t)m5 & reduce_mask_25; + c = (m5 >> 25); + m6 += c; + r6 = (uint32_t)m6 & reduce_mask_26; + c = (m6 >> 26); + m7 += c; + r7 = (uint32_t)m7 & reduce_mask_25; + c = (m7 >> 25); + m8 += c; + r8 = (uint32_t)m8 & reduce_mask_26; + c = (m8 >> 26); + m9 += c; + r9 = (uint32_t)m9 & reduce_mask_25; + p = (uint32_t)(m9 >> 25); + m0 = r0 + mul32x32_64(p, 19); + r0 = (uint32_t)m0 & reduce_mask_26; + p = (uint32_t)(m0 >> 26); + r1 += p; + } while(--count); + + out[0] = r0; + out[1] = r1; + out[2] = r2; + out[3] = r3; + out[4] = r4; + out[5] = r5; + out[6] = r6; + out[7] = r7; + out[8] = r8; + out[9] = r9; +} + +/* Take a little-endian, 32-byte number and expand it into polynomial form */ +void curve25519_expand(bignum25519 out, const unsigned char in[32]) { + uint32_t x0 = 0, x1 = 0, x2 = 0, x3 = 0, x4 = 0, x5 = 0, x6 = 0, x7 = 0; +#define F(s) \ + ((((uint32_t)in[s + 0])) | (((uint32_t)in[s + 1]) << 8) | (((uint32_t)in[s + 2]) << 16) | \ + (((uint32_t)in[s + 3]) << 24)) + x0 = F(0); + x1 = F(4); + x2 = F(8); + x3 = F(12); + x4 = F(16); + x5 = F(20); + x6 = F(24); + x7 = F(28); +#undef F + + out[0] = (x0)&reduce_mask_26; + out[1] = ((((uint64_t)x1 << 32) | x0) >> 26) & reduce_mask_25; + out[2] = ((((uint64_t)x2 << 32) | x1) >> 19) & reduce_mask_26; + out[3] = ((((uint64_t)x3 << 32) | x2) >> 13) & reduce_mask_25; + out[4] = ((x3) >> 6) & reduce_mask_26; + out[5] = (x4)&reduce_mask_25; + out[6] = ((((uint64_t)x5 << 32) | x4) >> 25) & reduce_mask_26; + out[7] = ((((uint64_t)x6 << 32) | x5) >> 19) & reduce_mask_25; + out[8] = ((((uint64_t)x7 << 32) | x6) >> 12) & reduce_mask_26; + out[9] = ((x7) >> 6) & reduce_mask_25; /* ignore the top bit */ +} + +/* Take a fully reduced polynomial form number and contract it into a + * little-endian, 32-byte array + */ +void curve25519_contract(unsigned char out[32], const bignum25519 in) { + bignum25519 f = {0}; + curve25519_copy(f, in); + +#define carry_pass() \ + f[1] += f[0] >> 26; \ + f[0] &= reduce_mask_26; \ + f[2] += f[1] >> 25; \ + f[1] &= reduce_mask_25; \ + f[3] += f[2] >> 26; \ + f[2] &= reduce_mask_26; \ + f[4] += f[3] >> 25; \ + f[3] &= reduce_mask_25; \ + f[5] += f[4] >> 26; \ + f[4] &= reduce_mask_26; \ + f[6] += f[5] >> 25; \ + f[5] &= reduce_mask_25; \ + f[7] += f[6] >> 26; \ + f[6] &= reduce_mask_26; \ + f[8] += f[7] >> 25; \ + f[7] &= reduce_mask_25; \ + f[9] += f[8] >> 26; \ + f[8] &= reduce_mask_26; + +#define carry_pass_full() \ + carry_pass() f[0] += 19 * (f[9] >> 25); \ + f[9] &= reduce_mask_25; + +#define carry_pass_final() carry_pass() f[9] &= reduce_mask_25; + + carry_pass_full() carry_pass_full() + + /* now t is between 0 and 2^255-1, properly carried. */ + /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */ + f[0] += 19; + carry_pass_full() + + /* now between 19 and 2^255-1 in both cases, and offset by 19. */ + f[0] += (reduce_mask_26 + 1) - 19; + f[1] += (reduce_mask_25 + 1) - 1; + f[2] += (reduce_mask_26 + 1) - 1; + f[3] += (reduce_mask_25 + 1) - 1; + f[4] += (reduce_mask_26 + 1) - 1; + f[5] += (reduce_mask_25 + 1) - 1; + f[6] += (reduce_mask_26 + 1) - 1; + f[7] += (reduce_mask_25 + 1) - 1; + f[8] += (reduce_mask_26 + 1) - 1; + f[9] += (reduce_mask_25 + 1) - 1; + + /* now between 2^255 and 2^256-20, and offset by 2^255. */ + carry_pass_final() + +#undef carry_pass +#undef carry_full +#undef carry_final + + f[1] <<= 2; + f[2] <<= 3; + f[3] <<= 5; + f[4] <<= 6; + f[6] <<= 1; + f[7] <<= 3; + f[8] <<= 4; + f[9] <<= 6; + +#define F(i, s) \ + out[s + 0] |= (unsigned char)(f[i] & 0xff); \ + out[s + 1] = (unsigned char)((f[i] >> 8) & 0xff); \ + out[s + 2] = (unsigned char)((f[i] >> 16) & 0xff); \ + out[s + 3] = (unsigned char)((f[i] >> 24) & 0xff); + + out[0] = 0; + out[16] = 0; + F(0, 0); + F(1, 3); + F(2, 6); + F(3, 9); + F(4, 12); + F(5, 16); + F(6, 19); + F(7, 22); + F(8, 25); + F(9, 28); +#undef F +} + +/* if (iswap) swap(a, b) */ +void curve25519_swap_conditional(bignum25519 a, bignum25519 b, uint32_t iswap) { + const uint32_t swap = (uint32_t)(-(int32_t)iswap); + uint32_t x0 = 0, x1 = 0, x2 = 0, x3 = 0, x4 = 0, x5 = 0, x6 = 0, x7 = 0, x8 = 0, x9 = 0; + + x0 = swap & (a[0] ^ b[0]); + a[0] ^= x0; + b[0] ^= x0; + x1 = swap & (a[1] ^ b[1]); + a[1] ^= x1; + b[1] ^= x1; + x2 = swap & (a[2] ^ b[2]); + a[2] ^= x2; + b[2] ^= x2; + x3 = swap & (a[3] ^ b[3]); + a[3] ^= x3; + b[3] ^= x3; + x4 = swap & (a[4] ^ b[4]); + a[4] ^= x4; + b[4] ^= x4; + x5 = swap & (a[5] ^ b[5]); + a[5] ^= x5; + b[5] ^= x5; + x6 = swap & (a[6] ^ b[6]); + a[6] ^= x6; + b[6] ^= x6; + x7 = swap & (a[7] ^ b[7]); + a[7] ^= x7; + b[7] ^= x7; + x8 = swap & (a[8] ^ b[8]); + a[8] ^= x8; + b[8] ^= x8; + x9 = swap & (a[9] ^ b[9]); + a[9] ^= x9; + b[9] ^= x9; +} + +void curve25519_set(bignum25519 r, uint32_t x) { + r[0] = x & reduce_mask_26; + x >>= 26; + r[1] = x & reduce_mask_25; + r[2] = 0; + r[3] = 0; + r[4] = 0; + r[5] = 0; + r[6] = 0; + r[7] = 0; + r[8] = 0; + r[9] = 0; +} + +void curve25519_set_d(bignum25519 r) { + curve25519_copy(r, ge25519_ecd); +} + +void curve25519_set_2d(bignum25519 r) { + curve25519_copy(r, ge25519_ec2d); +} + +void curve25519_set_sqrtneg1(bignum25519 r) { + curve25519_copy(r, ge25519_sqrtneg1); +} + +int curve25519_isnegative(const bignum25519 f) { + unsigned char s[32] = {0}; + curve25519_contract(s, f); + return s[0] & 1; +} + +int curve25519_isnonzero(const bignum25519 f) { + unsigned char s[32] = {0}; + curve25519_contract(s, f); + return ((((int)(s[0] | s[1] | s[2] | s[3] | s[4] | s[5] | s[6] | s[7] | s[8] | s[9] | s[10] | s[11] | s[12] | s[13] | s[14] | s[15] | s[16] | s[17] | s[18] | s[19] | s[20] | s[21] | s[22] | s[23] | s[24] | s[25] | s[26] | s[27] | s[28] | s[29] | s[30] | s[31]) - + 1) >> + 8) + + 1) & + 0x1; +} + +void curve25519_reduce(bignum25519 out, const bignum25519 in) { + uint32_t c = 0; + out[0] = in[0]; + c = (out[0] >> 26); + out[0] &= reduce_mask_26; + out[1] = in[1] + c; + c = (out[1] >> 25); + out[1] &= reduce_mask_25; + out[2] = in[2] + c; + c = (out[2] >> 26); + out[2] &= reduce_mask_26; + out[3] = in[3] + c; + c = (out[3] >> 25); + out[3] &= reduce_mask_25; + out[4] = in[4] + c; + c = (out[4] >> 26); + out[4] &= reduce_mask_26; + out[5] = in[5] + c; + c = (out[5] >> 25); + out[5] &= reduce_mask_25; + out[6] = in[6] + c; + c = (out[6] >> 26); + out[6] &= reduce_mask_26; + out[7] = in[7] + c; + c = (out[7] >> 25); + out[7] &= reduce_mask_25; + out[8] = in[8] + c; + c = (out[8] >> 26); + out[8] &= reduce_mask_26; + out[9] = in[9] + c; + c = (out[9] >> 25); + out[9] &= reduce_mask_25; + out[0] += 19 * c; +} + +void curve25519_divpowm1(bignum25519 r, const bignum25519 u, const bignum25519 v) { + bignum25519 v3 = {0}, uv7 = {0}, t0 = {0}, t1 = {0}, t2 = {0}; + int i = 0; + + curve25519_square(v3, v); + curve25519_mul(v3, v3, v); /* v3 = v^3 */ + curve25519_square(uv7, v3); + curve25519_mul(uv7, uv7, v); + curve25519_mul(uv7, uv7, u); /* uv7 = uv^7 */ + + /*fe_pow22523(uv7, uv7);*/ + /* From fe_pow22523.c */ + + curve25519_square(t0, uv7); + curve25519_square(t1, t0); + curve25519_square(t1, t1); + curve25519_mul(t1, uv7, t1); + curve25519_mul(t0, t0, t1); + curve25519_square(t0, t0); + curve25519_mul(t0, t1, t0); + curve25519_square(t1, t0); + for(i = 0; i < 4; ++i) { + curve25519_square(t1, t1); + } + curve25519_mul(t0, t1, t0); + curve25519_square(t1, t0); + for(i = 0; i < 9; ++i) { + curve25519_square(t1, t1); + } + curve25519_mul(t1, t1, t0); + curve25519_square(t2, t1); + for(i = 0; i < 19; ++i) { + curve25519_square(t2, t2); + } + curve25519_mul(t1, t2, t1); + for(i = 0; i < 10; ++i) { + curve25519_square(t1, t1); + } + curve25519_mul(t0, t1, t0); + curve25519_square(t1, t0); + for(i = 0; i < 49; ++i) { + curve25519_square(t1, t1); + } + curve25519_mul(t1, t1, t0); + curve25519_square(t2, t1); + for(i = 0; i < 99; ++i) { + curve25519_square(t2, t2); + } + curve25519_mul(t1, t2, t1); + for(i = 0; i < 50; ++i) { + curve25519_square(t1, t1); + } + curve25519_mul(t0, t1, t0); + curve25519_square(t0, t0); + curve25519_square(t0, t0); + curve25519_mul(t0, t0, uv7); + + /* End fe_pow22523.c */ + /* t0 = (uv^7)^((q-5)/8) */ + curve25519_mul(t0, t0, v3); + curve25519_mul(r, t0, u); /* u^(m+1)v^(-(m+1)) */ +} + +void curve25519_expand_reduce(bignum25519 out, const unsigned char in[32]) { + uint32_t x0 = 0, x1 = 0, x2 = 0, x3 = 0, x4 = 0, x5 = 0, x6 = 0, x7 = 0; +#define F(s) \ + ((((uint32_t)in[s + 0])) | (((uint32_t)in[s + 1]) << 8) | (((uint32_t)in[s + 2]) << 16) | \ + (((uint32_t)in[s + 3]) << 24)) + x0 = F(0); + x1 = F(4); + x2 = F(8); + x3 = F(12); + x4 = F(16); + x5 = F(20); + x6 = F(24); + x7 = F(28); +#undef F + + out[0] = (x0)&reduce_mask_26; + out[1] = ((((uint64_t)x1 << 32) | x0) >> 26) & reduce_mask_25; + out[2] = ((((uint64_t)x2 << 32) | x1) >> 19) & reduce_mask_26; + out[3] = ((((uint64_t)x3 << 32) | x2) >> 13) & reduce_mask_25; + out[4] = ((x3) >> 6) & reduce_mask_26; + out[5] = (x4)&reduce_mask_25; + out[6] = ((((uint64_t)x5 << 32) | x4) >> 25) & reduce_mask_26; + out[7] = ((((uint64_t)x6 << 32) | x5) >> 19) & reduce_mask_25; + out[8] = ((((uint64_t)x7 << 32) | x6) >> 12) & reduce_mask_26; + out[9] = ((x7) >> 6); // & reduce_mask_25; /* ignore the top bit */ + out[0] += 19 * (out[9] >> 25); + out[9] &= reduce_mask_25; +} diff --git a/applications/external/flipbip/lib/crypto/ed25519_donna/curve25519_donna_32bit.h b/applications/external/flipbip/lib/crypto/ed25519_donna/curve25519_donna_32bit.h new file mode 100644 index 000000000..87bea94f9 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/ed25519_donna/curve25519_donna_32bit.h @@ -0,0 +1,79 @@ +/* + Public domain by Andrew M. + See: https://github.com/floodyberry/curve25519-donna + + 32 bit integer curve25519 implementation +*/ + +typedef uint32_t bignum25519[10]; + +/* out = in */ +void curve25519_copy(bignum25519 out, const bignum25519 in); + +/* out = a + b */ +void curve25519_add(bignum25519 out, const bignum25519 a, const bignum25519 b); + +void curve25519_add_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b); + +void curve25519_add_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b); + +/* out = a - b */ +void curve25519_sub(bignum25519 out, const bignum25519 a, const bignum25519 b); + +/* out = in * scalar */ +void curve25519_scalar_product(bignum25519 out, const bignum25519 in, const uint32_t scalar); + +/* out = a - b, where a is the result of a basic op (add,sub) */ +void curve25519_sub_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b); + +void curve25519_sub_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b); + +/* out = -a */ +void curve25519_neg(bignum25519 out, const bignum25519 a); + +/* out = a * b */ +#define curve25519_mul_noinline curve25519_mul +void curve25519_mul(bignum25519 out, const bignum25519 a, const bignum25519 b); + +/* out = in * in */ +void curve25519_square(bignum25519 out, const bignum25519 in); + +/* out = in ^ (2 * count) */ +void curve25519_square_times(bignum25519 out, const bignum25519 in, int count); + +/* Take a little-endian, 32-byte number and expand it into polynomial form */ +void curve25519_expand(bignum25519 out, const unsigned char in[32]); + +/* Take a fully reduced polynomial form number and contract it into a + * little-endian, 32-byte array + */ +void curve25519_contract(unsigned char out[32], const bignum25519 in); + +/* if (iswap) swap(a, b) */ +void curve25519_swap_conditional(bignum25519 a, bignum25519 b, uint32_t iswap); + +/* uint32_t to Zmod(2^255-19) */ +void curve25519_set(bignum25519 r, uint32_t x); + +/* set d */ +void curve25519_set_d(bignum25519 r); + +/* set 2d */ +void curve25519_set_2d(bignum25519 r); + +/* set sqrt(-1) */ +void curve25519_set_sqrtneg1(bignum25519 r); + +/* constant time Zmod(2^255-19) negative test */ +int curve25519_isnegative(const bignum25519 f); + +/* constant time Zmod(2^255-19) non-zero test */ +int curve25519_isnonzero(const bignum25519 f); + +/* reduce Zmod(2^255-19) */ +void curve25519_reduce(bignum25519 r, const bignum25519 in); + +void curve25519_divpowm1(bignum25519 r, const bignum25519 u, const bignum25519 v); + +/* Zmod(2^255-19) from byte array to bignum25519 expansion with modular reduction */ +void curve25519_expand_reduce(bignum25519 out, const unsigned char in[32]); diff --git a/applications/external/flipbip/lib/crypto/ed25519_donna/curve25519_donna_helpers.c b/applications/external/flipbip/lib/crypto/ed25519_donna/curve25519_donna_helpers.c new file mode 100644 index 000000000..22a7b0254 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/ed25519_donna/curve25519_donna_helpers.c @@ -0,0 +1,66 @@ +/* + Public domain by Andrew M. + See: https://github.com/floodyberry/curve25519-donna + + Curve25519 implementation agnostic helpers +*/ + +#include "ed25519_donna.h" + +/* + * In: b = 2^5 - 2^0 + * Out: b = 2^250 - 2^0 + */ +void curve25519_pow_two5mtwo0_two250mtwo0(bignum25519 b) { + bignum25519 ALIGN(16) t0 = {0}, c = {0}; + + /* 2^5 - 2^0 */ /* b */ + /* 2^10 - 2^5 */ curve25519_square_times(t0, b, 5); + /* 2^10 - 2^0 */ curve25519_mul_noinline(b, t0, b); + /* 2^20 - 2^10 */ curve25519_square_times(t0, b, 10); + /* 2^20 - 2^0 */ curve25519_mul_noinline(c, t0, b); + /* 2^40 - 2^20 */ curve25519_square_times(t0, c, 20); + /* 2^40 - 2^0 */ curve25519_mul_noinline(t0, t0, c); + /* 2^50 - 2^10 */ curve25519_square_times(t0, t0, 10); + /* 2^50 - 2^0 */ curve25519_mul_noinline(b, t0, b); + /* 2^100 - 2^50 */ curve25519_square_times(t0, b, 50); + /* 2^100 - 2^0 */ curve25519_mul_noinline(c, t0, b); + /* 2^200 - 2^100 */ curve25519_square_times(t0, c, 100); + /* 2^200 - 2^0 */ curve25519_mul_noinline(t0, t0, c); + /* 2^250 - 2^50 */ curve25519_square_times(t0, t0, 50); + /* 2^250 - 2^0 */ curve25519_mul_noinline(b, t0, b); +} + +/* + * z^(p - 2) = z(2^255 - 21) + */ +void curve25519_recip(bignum25519 out, const bignum25519 z) { + bignum25519 ALIGN(16) a = {0}, t0 = {0}, b = {0}; + + /* 2 */ curve25519_square_times(a, z, 1); /* a = 2 */ + /* 8 */ curve25519_square_times(t0, a, 2); + /* 9 */ curve25519_mul_noinline(b, t0, z); /* b = 9 */ + /* 11 */ curve25519_mul_noinline(a, b, a); /* a = 11 */ + /* 22 */ curve25519_square_times(t0, a, 1); + /* 2^5 - 2^0 = 31 */ curve25519_mul_noinline(b, t0, b); + /* 2^250 - 2^0 */ curve25519_pow_two5mtwo0_two250mtwo0(b); + /* 2^255 - 2^5 */ curve25519_square_times(b, b, 5); + /* 2^255 - 21 */ curve25519_mul_noinline(out, b, a); +} + +/* + * z^((p-5)/8) = z^(2^252 - 3) + */ +void curve25519_pow_two252m3(bignum25519 two252m3, const bignum25519 z) { + bignum25519 ALIGN(16) b, c, t0; + + /* 2 */ curve25519_square_times(c, z, 1); /* c = 2 */ + /* 8 */ curve25519_square_times(t0, c, 2); /* t0 = 8 */ + /* 9 */ curve25519_mul_noinline(b, t0, z); /* b = 9 */ + /* 11 */ curve25519_mul_noinline(c, b, c); /* c = 11 */ + /* 22 */ curve25519_square_times(t0, c, 1); + /* 2^5 - 2^0 = 31 */ curve25519_mul_noinline(b, t0, b); + /* 2^250 - 2^0 */ curve25519_pow_two5mtwo0_two250mtwo0(b); + /* 2^252 - 2^2 */ curve25519_square_times(b, b, 2); + /* 2^252 - 3 */ curve25519_mul_noinline(two252m3, b, z); +} diff --git a/applications/external/flipbip/lib/crypto/ed25519_donna/curve25519_donna_helpers.h b/applications/external/flipbip/lib/crypto/ed25519_donna/curve25519_donna_helpers.h new file mode 100644 index 000000000..62fde9099 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/ed25519_donna/curve25519_donna_helpers.h @@ -0,0 +1,22 @@ +/* + Public domain by Andrew M. + See: https://github.com/floodyberry/curve25519-donna + + Curve25519 implementation agnostic helpers +*/ + +/* + * In: b = 2^5 - 2^0 + * Out: b = 2^250 - 2^0 + */ +void curve25519_pow_two5mtwo0_two250mtwo0(bignum25519 b); + +/* + * z^(p - 2) = z(2^255 - 21) + */ +void curve25519_recip(bignum25519 out, const bignum25519 z); + +/* + * z^((p-5)/8) = z^(2^252 - 3) + */ +void curve25519_pow_two252m3(bignum25519 two252m3, const bignum25519 z); diff --git a/applications/external/flipbip/lib/crypto/ed25519_donna/curve25519_donna_scalarmult_base.c b/applications/external/flipbip/lib/crypto/ed25519_donna/curve25519_donna_scalarmult_base.c new file mode 100644 index 000000000..ff162869a --- /dev/null +++ b/applications/external/flipbip/lib/crypto/ed25519_donna/curve25519_donna_scalarmult_base.c @@ -0,0 +1,70 @@ +#include "ed25519_donna.h" +#include "ed25519.h" + +/* Calculates nQ where Q is the x-coordinate of a point on the curve + * + * mypublic: the packed little endian x coordinate of the resulting curve point + * n: a little endian, 32-byte number + * basepoint: a packed little endian point of the curve + */ + +void curve25519_scalarmult_donna( + curve25519_key mypublic, + const curve25519_key n, + const curve25519_key basepoint) { + bignum25519 nqpqx = {1}, nqpqz = {0}, nqz = {1}, nqx = {0}; + bignum25519 q = {0}, qx = {0}, qpqx = {0}, qqx = {0}, zzz = {0}, zmone = {0}; + size_t bit = 0, lastbit = 0; + int32_t i = 0; + + curve25519_expand(q, basepoint); + curve25519_copy(nqx, q); + + /* bit 255 is always 0, and bit 254 is always 1, so skip bit 255 and + start pre-swapped on bit 254 */ + lastbit = 1; + + /* we are doing bits 254..3 in the loop, but are swapping in bits 253..2 */ + for(i = 253; i >= 2; i--) { + curve25519_add(qx, nqx, nqz); + curve25519_sub(nqz, nqx, nqz); + curve25519_add(qpqx, nqpqx, nqpqz); + curve25519_sub(nqpqz, nqpqx, nqpqz); + curve25519_mul(nqpqx, qpqx, nqz); + curve25519_mul(nqpqz, qx, nqpqz); + curve25519_add(qqx, nqpqx, nqpqz); + curve25519_sub(nqpqz, nqpqx, nqpqz); + curve25519_square(nqpqz, nqpqz); + curve25519_square(nqpqx, qqx); + curve25519_mul(nqpqz, nqpqz, q); + curve25519_square(qx, qx); + curve25519_square(nqz, nqz); + curve25519_mul(nqx, qx, nqz); + curve25519_sub(nqz, qx, nqz); + curve25519_scalar_product(zzz, nqz, 121665); + curve25519_add(zzz, zzz, qx); + curve25519_mul(nqz, nqz, zzz); + + bit = (n[i / 8] >> (i & 7)) & 1; + curve25519_swap_conditional(nqx, nqpqx, bit ^ lastbit); + curve25519_swap_conditional(nqz, nqpqz, bit ^ lastbit); + lastbit = bit; + } + + /* the final 3 bits are always zero, so we only need to double */ + for(i = 0; i < 3; i++) { + curve25519_add(qx, nqx, nqz); + curve25519_sub(nqz, nqx, nqz); + curve25519_square(qx, qx); + curve25519_square(nqz, nqz); + curve25519_mul(nqx, qx, nqz); + curve25519_sub(nqz, qx, nqz); + curve25519_scalar_product(zzz, nqz, 121665); + curve25519_add(zzz, zzz, qx); + curve25519_mul(nqz, nqz, zzz); + } + + curve25519_recip(zmone, nqz); + curve25519_mul(nqz, nqx, zmone); + curve25519_contract(mypublic, nqz); +} diff --git a/applications/external/flipbip/lib/crypto/ed25519_donna/curve25519_donna_scalarmult_base.h b/applications/external/flipbip/lib/crypto/ed25519_donna/curve25519_donna_scalarmult_base.h new file mode 100644 index 000000000..c6f18ed60 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/ed25519_donna/curve25519_donna_scalarmult_base.h @@ -0,0 +1,11 @@ +/* Calculates nQ where Q is the x-coordinate of a point on the curve + * + * mypublic: the packed little endian x coordinate of the resulting curve point + * n: a little endian, 32-byte number + * basepoint: a packed little endian point of the curve + */ + +void curve25519_scalarmult_donna( + curve25519_key mypublic, + const curve25519_key n, + const curve25519_key basepoint); diff --git a/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519.c b/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519.c new file mode 100644 index 000000000..2ccc2021d --- /dev/null +++ b/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519.c @@ -0,0 +1,336 @@ +/* + Public domain by Andrew M. + + Ed25519 reference implementation using Ed25519-donna +*/ + +/* define ED25519_SUFFIX to have it appended to the end of each public function */ +#ifdef ED25519_SUFFIX +#define ED25519_FN3(fn, suffix) fn##suffix +#define ED25519_FN2(fn, suffix) ED25519_FN3(fn, suffix) +#define ED25519_FN(fn) ED25519_FN2(fn, ED25519_SUFFIX) +#else +#define ED25519_FN(fn) fn +#endif + +#include "ed25519_donna.h" +#include "ed25519.h" + +#include "ed25519_hash_custom.h" +#include "../rand.h" +#include "../memzero.h" + +/* + Generates a (extsk[0..31]) and aExt (extsk[32..63]) +*/ +DONNA_INLINE static void ed25519_extsk(hash_512bits extsk, const ed25519_secret_key sk) { + ed25519_hash(extsk, sk, 32); + extsk[0] &= 248; + extsk[31] &= 127; + extsk[31] |= 64; +} + +static void ed25519_hram( + hash_512bits hram, + const ed25519_public_key R, + const ed25519_public_key pk, + const unsigned char* m, + size_t mlen) { + ed25519_hash_context ctx; + ed25519_hash_init(&ctx); + ed25519_hash_update(&ctx, R, 32); + ed25519_hash_update(&ctx, pk, 32); + ed25519_hash_update(&ctx, m, mlen); + ed25519_hash_final(&ctx, hram); +} + +void ED25519_FN(ed25519_publickey)(const ed25519_secret_key sk, ed25519_public_key pk) { + hash_512bits extsk = {0}; + ed25519_extsk(extsk, sk); + ed25519_publickey_ext(extsk, pk); + memzero(&extsk, sizeof(extsk)); +} + +void ED25519_FN(ed25519_cosi_commit)(ed25519_secret_key nonce, ed25519_public_key commitment) { + bignum256modm r = {0}; + ge25519 ALIGN(16) R; + unsigned char extnonce[64] = {0}; + + /* r = random512 mod L */ + random_buffer(extnonce, sizeof(extnonce)); + expand256_modm(r, extnonce, sizeof(extnonce)); + memzero(&extnonce, sizeof(extnonce)); + contract256_modm(nonce, r); + + /* R = rB */ + ge25519_scalarmult_base_niels(&R, ge25519_niels_base_multiples, r); + memzero(&r, sizeof(r)); + ge25519_pack(commitment, &R); +} + +int ED25519_FN(ed25519_cosi_sign)( + const unsigned char* m, + size_t mlen, + const ed25519_secret_key sk, + const ed25519_secret_key nonce, + const ed25519_public_key R, + const ed25519_public_key pk, + ed25519_cosi_signature sig) { + bignum256modm r = {0}, S = {0}, a = {0}; + hash_512bits extsk = {0}, hram = {0}; + + ed25519_extsk(extsk, sk); + + /* r */ + expand_raw256_modm(r, nonce); + if(!is_reduced256_modm(r)) return -1; + + /* S = H(R,A,m).. */ + ed25519_hram(hram, R, pk, m, mlen); + expand256_modm(S, hram, 64); + + /* S = H(R,A,m)a */ + expand256_modm(a, extsk, 32); + memzero(&extsk, sizeof(extsk)); + mul256_modm(S, S, a); + memzero(&a, sizeof(a)); + + /* S = (r + H(R,A,m)a) */ + add256_modm(S, S, r); + memzero(&r, sizeof(r)); + + /* S = (r + H(R,A,m)a) mod L */ + contract256_modm(sig, S); + + return 0; +} + +void ED25519_FN(ed25519_sign_ext)( + const unsigned char* m, + size_t mlen, + const ed25519_secret_key sk, + const ed25519_secret_key skext, + ed25519_signature RS) { + ed25519_hash_context ctx; + bignum256modm r = {0}, S = {0}, a = {0}; + ge25519 ALIGN(16) R = {0}; + ge25519 ALIGN(16) A = {0}; + ed25519_public_key pk = {0}; + hash_512bits extsk = {0}, hashr = {0}, hram = {0}; + + /* we don't stretch the key through hashing first since its already 64 bytes */ + + memcpy(extsk, sk, 32); + memcpy(extsk + 32, skext, 32); + + /* r = H(aExt[32..64], m) */ + ed25519_hash_init(&ctx); + ed25519_hash_update(&ctx, extsk + 32, 32); + ed25519_hash_update(&ctx, m, mlen); + ed25519_hash_final(&ctx, hashr); + expand256_modm(r, hashr, 64); + memzero(&hashr, sizeof(hashr)); + + /* R = rB */ + ge25519_scalarmult_base_niels(&R, ge25519_niels_base_multiples, r); + ge25519_pack(RS, &R); + + /* a = aExt[0..31] */ + expand256_modm(a, extsk, 32); + memzero(&extsk, sizeof(extsk)); + + /* A = aB */ + ge25519_scalarmult_base_niels(&A, ge25519_niels_base_multiples, a); + ge25519_pack(pk, &A); + + /* S = H(R,A,m).. */ + ed25519_hram(hram, RS, pk, m, mlen); + expand256_modm(S, hram, 64); + + /* S = H(R,A,m)a */ + mul256_modm(S, S, a); + memzero(&a, sizeof(a)); + + /* S = (r + H(R,A,m)a) */ + add256_modm(S, S, r); + memzero(&r, sizeof(r)); + + /* S = (r + H(R,A,m)a) mod L */ + contract256_modm(RS + 32, S); +} + +void ED25519_FN(ed25519_sign)( + const unsigned char* m, + size_t mlen, + const ed25519_secret_key sk, + ed25519_signature RS) { + hash_512bits extsk = {0}; + ed25519_extsk(extsk, sk); + ED25519_FN(ed25519_sign_ext)(m, mlen, extsk, extsk + 32, RS); + memzero(&extsk, sizeof(extsk)); +} + +int ED25519_FN(ed25519_sign_open)( + const unsigned char* m, + size_t mlen, + const ed25519_public_key pk, + const ed25519_signature RS) { + ge25519 ALIGN(16) R = {0}, A = {0}; + hash_512bits hash = {0}; + bignum256modm hram = {0}, S = {0}; + unsigned char checkR[32] = {0}; + + if((RS[63] & 224) || !ge25519_unpack_negative_vartime(&A, pk)) return -1; + + /* hram = H(R,A,m) */ + ed25519_hram(hash, RS, pk, m, mlen); + expand256_modm(hram, hash, 64); + + /* S */ + expand_raw256_modm(S, RS + 32); + if(!is_reduced256_modm(S)) return -1; + + /* SB - H(R,A,m)A */ + ge25519_double_scalarmult_vartime(&R, &A, hram, S); + ge25519_pack(checkR, &R); + + /* check that R = SB - H(R,A,m)A */ + return ed25519_verify(RS, checkR, 32) ? 0 : -1; +} + +int ED25519_FN(ed25519_scalarmult)( + ed25519_public_key res, + const ed25519_secret_key sk, + const ed25519_public_key pk) { + bignum256modm a = {0}; + ge25519 ALIGN(16) A = {0}, P = {0}; + hash_512bits extsk = {0}; + + ed25519_extsk(extsk, sk); + expand256_modm(a, extsk, 32); + memzero(&extsk, sizeof(extsk)); + + if(!ge25519_unpack_negative_vartime(&P, pk)) { + return -1; + } + + ge25519_scalarmult(&A, &P, a); + memzero(&a, sizeof(a)); + curve25519_neg(A.x, A.x); + ge25519_pack(res, &A); + return 0; +} + +#ifndef ED25519_SUFFIX + +#include "curve25519_donna_scalarmult_base.h" + +void ed25519_publickey_ext(const ed25519_secret_key extsk, ed25519_public_key pk) { + bignum256modm a = {0}; + ge25519 ALIGN(16) A = {0}; + + expand256_modm(a, extsk, 32); + + /* A = aB */ + ge25519_scalarmult_base_niels(&A, ge25519_niels_base_multiples, a); + memzero(&a, sizeof(a)); + ge25519_pack(pk, &A); +} + +int ed25519_cosi_combine_publickeys( + ed25519_public_key res, + CONST ed25519_public_key* pks, + size_t n) { + size_t i = 0; + ge25519 P = {0}; + ge25519_pniels sump = {0}; + ge25519_p1p1 sump1 = {0}; + + if(n == 1) { + memcpy(res, pks, sizeof(ed25519_public_key)); + return 0; + } + if(!ge25519_unpack_negative_vartime(&P, pks[i++])) { + return -1; + } + ge25519_full_to_pniels(&sump, &P); + while(i < n - 1) { + if(!ge25519_unpack_negative_vartime(&P, pks[i++])) { + return -1; + } + ge25519_pnielsadd(&sump, &P, &sump); + } + if(!ge25519_unpack_negative_vartime(&P, pks[i++])) { + return -1; + } + ge25519_pnielsadd_p1p1(&sump1, &P, &sump, 0); + ge25519_p1p1_to_partial(&P, &sump1); + curve25519_neg(P.x, P.x); + ge25519_pack(res, &P); + return 0; +} + +void ed25519_cosi_combine_signatures( + ed25519_signature res, + const ed25519_public_key R, + CONST ed25519_cosi_signature* sigs, + size_t n) { + bignum256modm s = {0}, t = {0}; + size_t i = 0; + + expand256_modm(s, sigs[i++], 32); + while(i < n) { + expand256_modm(t, sigs[i++], 32); + add256_modm(s, s, t); + } + memcpy(res, R, 32); + contract256_modm(res + 32, s); +} + +/* + Fast Curve25519 basepoint scalar multiplication +*/ +void curve25519_scalarmult_basepoint(curve25519_key pk, const curve25519_key e) { + curve25519_key ec = {0}; + bignum256modm s = {0}; + bignum25519 ALIGN(16) yplusz = {0}, zminusy = {0}; + ge25519 ALIGN(16) p = {0}; + size_t i = 0; + + /* clamp */ + for(i = 0; i < 32; i++) ec[i] = e[i]; + ec[0] &= 248; + ec[31] &= 127; + ec[31] |= 64; + + expand_raw256_modm(s, ec); + memzero(&ec, sizeof(ec)); + + /* scalar * basepoint */ + ge25519_scalarmult_base_niels(&p, ge25519_niels_base_multiples, s); + memzero(&s, sizeof(s)); + + /* u = (y + z) / (z - y) */ + curve25519_add(yplusz, p.y, p.z); + curve25519_sub(zminusy, p.z, p.y); + curve25519_recip(zminusy, zminusy); + curve25519_mul(yplusz, yplusz, zminusy); + curve25519_contract(pk, yplusz); +} + +void curve25519_scalarmult( + curve25519_key mypublic, + const curve25519_key secret, + const curve25519_key basepoint) { + curve25519_key e = {0}; + size_t i = 0; + + for(i = 0; i < 32; ++i) e[i] = secret[i]; + e[0] &= 0xf8; + e[31] &= 0x7f; + e[31] |= 0x40; + curve25519_scalarmult_donna(mypublic, e, basepoint); + memzero(&e, sizeof(e)); +} + +#endif // ED25519_SUFFIX diff --git a/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519.h b/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519.h new file mode 100644 index 000000000..f2f0017b6 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519.h @@ -0,0 +1,78 @@ +#ifndef ED25519_H +#define ED25519_H + +#include "../options.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +typedef unsigned char ed25519_signature[64]; +typedef unsigned char ed25519_public_key[32]; +typedef unsigned char ed25519_secret_key[32]; + +typedef unsigned char curve25519_key[32]; + +typedef unsigned char ed25519_cosi_signature[32]; + +void ed25519_publickey(const ed25519_secret_key sk, ed25519_public_key pk); +void ed25519_publickey_ext(const ed25519_secret_key extsk, ed25519_public_key pk); + +int ed25519_sign_open( + const unsigned char* m, + size_t mlen, + const ed25519_public_key pk, + const ed25519_signature RS); +void ed25519_sign( + const unsigned char* m, + size_t mlen, + const ed25519_secret_key sk, + ed25519_signature RS); +void ed25519_sign_ext( + const unsigned char* m, + size_t mlen, + const ed25519_secret_key sk, + const ed25519_secret_key skext, + ed25519_signature RS); + +int ed25519_scalarmult( + ed25519_public_key res, + const ed25519_secret_key sk, + const ed25519_public_key pk); + +void curve25519_scalarmult( + curve25519_key mypublic, + const curve25519_key secret, + const curve25519_key basepoint); +void curve25519_scalarmult_basepoint(curve25519_key mypublic, const curve25519_key secret); + +#if !defined(__GNUC__) || __GNUC__ > 4 +#define CONST const +#else +#define CONST +#endif + +int ed25519_cosi_combine_publickeys( + ed25519_public_key res, + CONST ed25519_public_key* pks, + size_t n); +void ed25519_cosi_combine_signatures( + ed25519_signature res, + const ed25519_public_key R, + CONST ed25519_cosi_signature* sigs, + size_t n); +void ed25519_cosi_commit(ed25519_secret_key nonce, ed25519_public_key commitment); +int ed25519_cosi_sign( + const unsigned char* m, + size_t mlen, + const ed25519_secret_key key, + const ed25519_secret_key nonce, + const ed25519_public_key R, + const ed25519_public_key pk, + ed25519_cosi_signature sig); + +#if defined(__cplusplus) +} +#endif + +#endif // ED25519_H diff --git a/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_donna.h b/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_donna.h new file mode 100644 index 000000000..00746ab8d --- /dev/null +++ b/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_donna.h @@ -0,0 +1,52 @@ +/* + Public domain by Andrew M. + Modified from the amd64-51-30k implementation by + Daniel J. Bernstein + Niels Duif + Tanja Lange + Peter Schwabe + Bo-Yin Yang +*/ + +#ifndef ED25519_DONNA_H +#define ED25519_DONNA_H + +#include "ed25519_donna_portable.h" + +#include "curve25519_donna_32bit.h" + +#include "curve25519_donna_helpers.h" + +#include "modm_donna_32bit.h" + +typedef unsigned char hash_512bits[64]; + +/* + * Arithmetic on the twisted Edwards curve -x^2 + y^2 = 1 + dx^2y^2 + * with d = -(121665/121666) = 37095705934669439343138083508754565189542113879843219016388785533085940283555 + * Base point: (15112221349535400772501151409588531511454012693041857206046113283949847762202,46316835694926478169428394003475163141307993866256225615783033603165251855960); + */ + +typedef struct ge25519_t { + bignum25519 x, y, z, t; +} ge25519; + +typedef struct ge25519_p1p1_t { + bignum25519 x, y, z, t; +} ge25519_p1p1; + +typedef struct ge25519_niels_t { + bignum25519 ysubx, xaddy, t2d; +} ge25519_niels; + +typedef struct ge25519_pniels_t { + bignum25519 ysubx, xaddy, z, t2d; +} ge25519_pniels; + +#include "ed25519_donna_basepoint_table.h" + +#include "ed25519_donna_32bit_tables.h" + +#include "ed25519_donna_impl_base.h" + +#endif diff --git a/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_donna_32bit_tables.c b/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_donna_32bit_tables.c new file mode 100644 index 000000000..4b932dd0f --- /dev/null +++ b/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_donna_32bit_tables.c @@ -0,0 +1,1049 @@ +#include "ed25519_donna.h" + +const ge25519 ALIGN(16) ge25519_basepoint = { + {0x0325d51a, + 0x018b5823, + 0x00f6592a, + 0x0104a92d, + 0x01a4b31d, + 0x01d6dc5c, + 0x027118fe, + 0x007fd814, + 0x013cd6e5, + 0x0085a4db}, + {0x02666658, + 0x01999999, + 0x00cccccc, + 0x01333333, + 0x01999999, + 0x00666666, + 0x03333333, + 0x00cccccc, + 0x02666666, + 0x01999999}, + {0x00000001, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000}, + {0x01b7dda3, + 0x01a2ace9, + 0x025eadbb, + 0x0003ba8a, + 0x0083c27e, + 0x00abe37d, + 0x01274732, + 0x00ccacdd, + 0x00fd78b7, + 0x019e1d7c}}; + +/* + d +*/ + +const bignum25519 ALIGN(16) ge25519_ecd = { + 0x035978a3, + 0x00d37284, + 0x03156ebd, + 0x006a0a0e, + 0x0001c029, + 0x0179e898, + 0x03a03cbb, + 0x01ce7198, + 0x02e2b6ff, + 0x01480db3}; + +const bignum25519 ALIGN(16) ge25519_ec2d = { + 0x02b2f159, + 0x01a6e509, + 0x022add7a, + 0x00d4141d, + 0x00038052, + 0x00f3d130, + 0x03407977, + 0x019ce331, + 0x01c56dff, + 0x00901b67}; + +/* + sqrt(-1) +*/ + +const bignum25519 ALIGN(16) ge25519_sqrtneg1 = { + 0x020ea0b0, + 0x0186c9d2, + 0x008f189d, + 0x0035697f, + 0x00bd0c60, + 0x01fbd7a7, + 0x02804c9e, + 0x01e16569, + 0x0004fc1d, + 0x00ae0c92}; + +const ge25519_niels ALIGN(16) ge25519_niels_sliding_multiples[32] = { + {{0x0340913e, + 0x000e4175, + 0x03d673a2, + 0x002e8a05, + 0x03f4e67c, + 0x008f8a09, + 0x00c21a34, + 0x004cf4b8, + 0x01298f81, + 0x0113f4be}, + {0x018c3b85, + 0x0124f1bd, + 0x01c325f7, + 0x0037dc60, + 0x033e4cb7, + 0x003d42c2, + 0x01a44c32, + 0x014ca4e1, + 0x03a33d4b, + 0x001f3e74}, + {0x037aaa68, + 0x00448161, + 0x0093d579, + 0x011e6556, + 0x009b67a0, + 0x0143598c, + 0x01bee5ee, + 0x00b50b43, + 0x0289f0c6, + 0x01bc45ed}}, + {{0x00fcd265, + 0x0047fa29, + 0x034faacc, + 0x01ef2e0d, + 0x00ef4d4f, + 0x014bd6bd, + 0x00f98d10, + 0x014c5026, + 0x007555bd, + 0x00aae456}, + {0x00ee9730, + 0x016c2a13, + 0x017155e4, + 0x01874432, + 0x00096a10, + 0x01016732, + 0x01a8014f, + 0x011e9823, + 0x01b9a80f, + 0x01e85938}, + {0x01d0d889, + 0x01a4cfc3, + 0x034c4295, + 0x0110e1ae, + 0x0162508c, + 0x00f2db4c, + 0x0072a2c6, + 0x0098da2e, + 0x02f12b9b, + 0x0168a09a}}, + {{0x0047d6ba, + 0x0060b0e9, + 0x0136eff2, + 0x008a5939, + 0x03540053, + 0x0064a087, + 0x02788e5c, + 0x00be7c67, + 0x033eb1b5, + 0x005529f9}, + {0x00a5bb33, + 0x00af1102, + 0x01a05442, + 0x001e3af7, + 0x02354123, + 0x00bfec44, + 0x01f5862d, + 0x00dd7ba3, + 0x03146e20, + 0x00a51733}, + {0x012a8285, + 0x00f6fc60, + 0x023f9797, + 0x003e85ee, + 0x009c3820, + 0x01bda72d, + 0x01b3858d, + 0x00d35683, + 0x0296b3bb, + 0x010eaaf9}}, + {{0x023221b1, + 0x01cb26aa, + 0x0074f74d, + 0x0099ddd1, + 0x01b28085, + 0x00192c3a, + 0x013b27c9, + 0x00fc13bd, + 0x01d2e531, + 0x0075bb75}, + {0x004ea3bf, + 0x00973425, + 0x001a4d63, + 0x01d59cee, + 0x01d1c0d4, + 0x00542e49, + 0x01294114, + 0x004fce36, + 0x029283c9, + 0x01186fa9}, + {0x01b8b3a2, + 0x00db7200, + 0x00935e30, + 0x003829f5, + 0x02cc0d7d, + 0x0077adf3, + 0x0220dd2c, + 0x0014ea53, + 0x01c6a0f9, + 0x01ea7eec}}, + {{0x039d8064, + 0x01885f80, + 0x00337e6d, + 0x01b7a902, + 0x02628206, + 0x015eb044, + 0x01e30473, + 0x0191f2d9, + 0x011fadc9, + 0x01270169}, + {0x02a8632f, + 0x0199e2a9, + 0x00d8b365, + 0x017a8de2, + 0x02994279, + 0x0086f5b5, + 0x0119e4e3, + 0x01eb39d6, + 0x0338add7, + 0x00d2e7b4}, + {0x0045af1b, + 0x013a2fe4, + 0x0245e0d6, + 0x014538ce, + 0x038bfe0f, + 0x01d4cf16, + 0x037e14c9, + 0x0160d55e, + 0x0021b008, + 0x01cf05c8}}, + {{0x01864348, + 0x01d6c092, + 0x0070262b, + 0x014bb844, + 0x00fb5acd, + 0x008deb95, + 0x003aaab5, + 0x00eff474, + 0x00029d5c, + 0x0062ad66}, + {0x02802ade, + 0x01c02122, + 0x01c4e5f7, + 0x00781181, + 0x039767fb, + 0x01703406, + 0x0342388b, + 0x01f5e227, + 0x022546d8, + 0x0109d6ab}, + {0x016089e9, + 0x00cb317f, + 0x00949b05, + 0x01099417, + 0x000c7ad2, + 0x011a8622, + 0x0088ccda, + 0x01290886, + 0x022b53df, + 0x00f71954}}, + {{0x027fbf93, + 0x01c04ecc, + 0x01ed6a0d, + 0x004cdbbb, + 0x02bbf3af, + 0x00ad5968, + 0x01591955, + 0x0094f3a2, + 0x02d17602, + 0x00099e20}, + {0x02007f6d, + 0x003088a8, + 0x03db77ee, + 0x00d5ade6, + 0x02fe12ce, + 0x0107ba07, + 0x0107097d, + 0x00482a6f, + 0x02ec346f, + 0x008d3f5f}, + {0x032ea378, + 0x0028465c, + 0x028e2a6c, + 0x018efc6e, + 0x0090df9a, + 0x01a7e533, + 0x039bfc48, + 0x010c745d, + 0x03daa097, + 0x0125ee9b}}, + {{0x028ccf0b, + 0x00f36191, + 0x021ac081, + 0x012154c8, + 0x034e0a6e, + 0x01b25192, + 0x00180403, + 0x01d7eea1, + 0x00218d05, + 0x010ed735}, + {0x03cfeaa0, + 0x01b300c4, + 0x008da499, + 0x0068c4e1, + 0x0219230a, + 0x01f2d4d0, + 0x02defd60, + 0x00e565b7, + 0x017f12de, + 0x018788a4}, + {0x03d0b516, + 0x009d8be6, + 0x03ddcbb3, + 0x0071b9fe, + 0x03ace2bd, + 0x01d64270, + 0x032d3ec9, + 0x01084065, + 0x0210ae4d, + 0x01447584}}, + {{0x0020de87, + 0x00e19211, + 0x01b68102, + 0x00b5ac97, + 0x022873c0, + 0x01942d25, + 0x01271394, + 0x0102073f, + 0x02fe2482, + 0x01c69ff9}, + {0x010e9d81, + 0x019dbbe5, + 0x0089f258, + 0x006e06b8, + 0x02951883, + 0x018f1248, + 0x019b3237, + 0x00bc7553, + 0x024ddb85, + 0x01b4c964}, + {0x01c8c854, + 0x0060ae29, + 0x01406d8e, + 0x01cff2f9, + 0x00cff451, + 0x01778d0c, + 0x03ac8c41, + 0x01552e59, + 0x036559ee, + 0x011d1b12}}, + {{0x00741147, + 0x0151b219, + 0x01092690, + 0x00e877e6, + 0x01f4d6bb, + 0x0072a332, + 0x01cd3b03, + 0x00dadff2, + 0x0097db5e, + 0x0086598d}, + {0x01c69a2b, + 0x01decf1b, + 0x02c2fa6e, + 0x013b7c4f, + 0x037beac8, + 0x013a16b5, + 0x028e7bda, + 0x01f6e8ac, + 0x01e34fe9, + 0x01726947}, + {0x01f10e67, + 0x003c73de, + 0x022b7ea2, + 0x010f32c2, + 0x03ff776a, + 0x00142277, + 0x01d38b88, + 0x00776138, + 0x03c60822, + 0x01201140}}, + {{0x0236d175, + 0x0008748e, + 0x03c6476d, + 0x013f4cdc, + 0x02eed02a, + 0x00838a47, + 0x032e7210, + 0x018bcbb3, + 0x00858de4, + 0x01dc7826}, + {0x00a37fc7, + 0x0127b40b, + 0x01957884, + 0x011d30ad, + 0x02816683, + 0x016e0e23, + 0x00b76be4, + 0x012db115, + 0x02516506, + 0x0154ce62}, + {0x00451edf, + 0x00bd749e, + 0x03997342, + 0x01cc2c4c, + 0x00eb6975, + 0x01a59508, + 0x03a516cf, + 0x00c228ef, + 0x0168ff5a, + 0x01697b47}}, + {{0x00527359, + 0x01783156, + 0x03afd75c, + 0x00ce56dc, + 0x00e4b970, + 0x001cabe9, + 0x029e0f6d, + 0x0188850c, + 0x0135fefd, + 0x00066d80}, + {0x02150e83, + 0x01448abf, + 0x02bb0232, + 0x012bf259, + 0x033c8268, + 0x00711e20, + 0x03fc148f, + 0x005e0e70, + 0x017d8bf9, + 0x0112b2e2}, + {0x02134b83, + 0x001a0517, + 0x0182c3cc, + 0x00792182, + 0x0313d799, + 0x001a3ed7, + 0x0344547e, + 0x01f24a0d, + 0x03de6ad2, + 0x00543127}}, + {{0x00dca868, + 0x00618f27, + 0x015a1709, + 0x00ddc38a, + 0x0320fd13, + 0x0036168d, + 0x0371ab06, + 0x01783fc7, + 0x0391e05f, + 0x01e29b5d}, + {0x01471138, + 0x00fca542, + 0x00ca31cf, + 0x01ca7bad, + 0x0175bfbc, + 0x01a708ad, + 0x03bce212, + 0x01244215, + 0x0075bb99, + 0x01acad68}, + {0x03a0b976, + 0x01dc12d1, + 0x011aab17, + 0x00aba0ba, + 0x029806cd, + 0x0142f590, + 0x018fd8ea, + 0x01a01545, + 0x03c4ad55, + 0x01c971ff}}, + {{0x00d098c0, + 0x000afdc7, + 0x006cd230, + 0x01276af3, + 0x03f905b2, + 0x0102994c, + 0x002eb8a4, + 0x015cfbeb, + 0x025f855f, + 0x01335518}, + {0x01cf99b2, + 0x0099c574, + 0x01a69c88, + 0x00881510, + 0x01cd4b54, + 0x0112109f, + 0x008abdc5, + 0x0074647a, + 0x0277cb1f, + 0x01e53324}, + {0x02ac5053, + 0x01b109b0, + 0x024b095e, + 0x016997b3, + 0x02f26bb6, + 0x00311021, + 0x00197885, + 0x01d0a55a, + 0x03b6fcc8, + 0x01c020d5}}, + {{0x02584a34, + 0x00e7eee0, + 0x03257a03, + 0x011e95a3, + 0x011ead91, + 0x00536202, + 0x00b1ce24, + 0x008516c6, + 0x03669d6d, + 0x004ea4a8}, + {0x00773f01, + 0x0019c9ce, + 0x019f6171, + 0x01d4afde, + 0x02e33323, + 0x01ad29b6, + 0x02ead1dc, + 0x01ed51a5, + 0x01851ad0, + 0x001bbdfa}, + {0x00577de5, + 0x00ddc730, + 0x038b9952, + 0x00f281ae, + 0x01d50390, + 0x0002e071, + 0x000780ec, + 0x010d448d, + 0x01f8a2af, + 0x00f0a5b7}}, + {{0x031f2541, + 0x00d34bae, + 0x0323ff9d, + 0x003a056d, + 0x02e25443, + 0x00a1ad05, + 0x00d1bee8, + 0x002f7f8e, + 0x03007477, + 0x002a24b1}, + {0x0114a713, + 0x01457e76, + 0x032255d5, + 0x01cc647f, + 0x02a4bdef, + 0x0153d730, + 0x00118bcf, + 0x00f755ff, + 0x013490c7, + 0x01ea674e}, + {0x02bda3e8, + 0x00bb490d, + 0x00f291ea, + 0x000abf40, + 0x01dea321, + 0x002f9ce0, + 0x00b2b193, + 0x00fa54b5, + 0x0128302f, + 0x00a19d8b}}, + {{0x022ef5bd, + 0x01638af3, + 0x038c6f8a, + 0x01a33a3d, + 0x039261b2, + 0x01bb89b8, + 0x010bcf9d, + 0x00cf42a9, + 0x023d6f17, + 0x01da1bca}, + {0x00e35b25, + 0x000d824f, + 0x0152e9cf, + 0x00ed935d, + 0x020b8460, + 0x01c7b83f, + 0x00c969e5, + 0x01a74198, + 0x0046a9d9, + 0x00cbc768}, + {0x01597c6a, + 0x0144a99b, + 0x00a57551, + 0x0018269c, + 0x023c464c, + 0x0009b022, + 0x00ee39e1, + 0x0114c7f2, + 0x038a9ad2, + 0x01584c17}}, + {{0x03b0c0d5, + 0x00b30a39, + 0x038a6ce4, + 0x01ded83a, + 0x01c277a6, + 0x01010a61, + 0x0346d3eb, + 0x018d995e, + 0x02f2c57c, + 0x000c286b}, + {0x0092aed1, + 0x0125e37b, + 0x027ca201, + 0x001a6b6b, + 0x03290f55, + 0x0047ba48, + 0x018d916c, + 0x01a59062, + 0x013e35d4, + 0x0002abb1}, + {0x003ad2aa, + 0x007ddcc0, + 0x00c10f76, + 0x0001590b, + 0x002cfca6, + 0x000ed23e, + 0x00ee4329, + 0x00900f04, + 0x01c24065, + 0x0082fa70}}, + {{0x02025e60, + 0x003912b8, + 0x0327041c, + 0x017e5ee5, + 0x02c0ecec, + 0x015a0d1c, + 0x02b1ce7c, + 0x0062220b, + 0x0145067e, + 0x01a5d931}, + {0x009673a6, + 0x00e1f609, + 0x00927c2a, + 0x016faa37, + 0x01650ef0, + 0x016f63b5, + 0x03cd40e1, + 0x003bc38f, + 0x0361f0ac, + 0x01d42acc}, + {0x02f81037, + 0x008ca0e8, + 0x017e23d1, + 0x011debfe, + 0x01bcbb68, + 0x002e2563, + 0x03e8add6, + 0x000816e5, + 0x03fb7075, + 0x0153e5ac}}, + {{0x02b11ecd, + 0x016bf185, + 0x008f22ef, + 0x00e7d2bb, + 0x0225d92e, + 0x00ece785, + 0x00508873, + 0x017e16f5, + 0x01fbe85d, + 0x01e39a0e}, + {0x01669279, + 0x017c810a, + 0x024941f5, + 0x0023ebeb, + 0x00eb7688, + 0x005760f1, + 0x02ca4146, + 0x0073cde7, + 0x0052bb75, + 0x00f5ffa7}, + {0x03b8856b, + 0x00cb7dcd, + 0x02f14e06, + 0x001820d0, + 0x01d74175, + 0x00e59e22, + 0x03fba550, + 0x00484641, + 0x03350088, + 0x01c3c9a3}}, + {{0x00dcf355, + 0x0104481c, + 0x0022e464, + 0x01f73fe7, + 0x00e03325, + 0x0152b698, + 0x02ef769a, + 0x00973663, + 0x00039b8c, + 0x0101395b}, + {0x01805f47, + 0x019160ec, + 0x03832cd0, + 0x008b06eb, + 0x03d4d717, + 0x004cb006, + 0x03a75b8f, + 0x013b3d30, + 0x01cfad88, + 0x01f034d1}, + {0x0078338a, + 0x01c7d2e3, + 0x02bc2b23, + 0x018b3f05, + 0x0280d9aa, + 0x005f3d44, + 0x0220a95a, + 0x00eeeb97, + 0x0362aaec, + 0x00835d51}}, + {{0x01b9f543, + 0x013fac4d, + 0x02ad93ae, + 0x018ef464, + 0x0212cdf7, + 0x01138ba9, + 0x011583ab, + 0x019c3d26, + 0x028790b4, + 0x00e2e2b6}, + {0x033bb758, + 0x01f0dbf1, + 0x03734bd1, + 0x0129b1e5, + 0x02b3950e, + 0x003bc922, + 0x01a53ec8, + 0x018c5532, + 0x006f3cee, + 0x00ae3c79}, + {0x0351f95d, + 0x0012a737, + 0x03d596b8, + 0x017658fe, + 0x00ace54a, + 0x008b66da, + 0x0036c599, + 0x012a63a2, + 0x032ceba1, + 0x00126bac}}, + {{0x03dcfe7e, + 0x019f4f18, + 0x01c81aee, + 0x0044bc2b, + 0x00827165, + 0x014f7c13, + 0x03b430f0, + 0x00bf96cc, + 0x020c8d62, + 0x01471997}, + {0x01fc7931, + 0x001f42dd, + 0x00ba754a, + 0x005bd339, + 0x003fbe49, + 0x016b3930, + 0x012a159c, + 0x009f83b0, + 0x03530f67, + 0x01e57b85}, + {0x02ecbd81, + 0x0096c294, + 0x01fce4a9, + 0x017701a5, + 0x0175047d, + 0x00ee4a31, + 0x012686e5, + 0x008efcd4, + 0x0349dc54, + 0x01b3466f}}, + {{0x02179ca3, + 0x01d86414, + 0x03f0afd0, + 0x00305964, + 0x015c7428, + 0x0099711e, + 0x015d5442, + 0x00c71014, + 0x01b40b2e, + 0x01d483cf}, + {0x01afc386, + 0x01984859, + 0x036203ff, + 0x0045c6a8, + 0x0020a8aa, + 0x00990baa, + 0x03313f10, + 0x007ceede, + 0x027429e4, + 0x017806ce}, + {0x039357a1, + 0x0142f8f4, + 0x0294a7b6, + 0x00eaccf4, + 0x0259edb3, + 0x01311e6e, + 0x004d326f, + 0x0130c346, + 0x01ccef3c, + 0x01c424b2}}, + {{0x0364918c, + 0x00148fc0, + 0x01638a7b, + 0x01a1fd5b, + 0x028ad013, + 0x0081e5a4, + 0x01a54f33, + 0x0174e101, + 0x003d0257, + 0x003a856c}, + {0x00051dcf, + 0x00f62b1d, + 0x0143d0ad, + 0x0042adbd, + 0x000fda90, + 0x01743ceb, + 0x0173e5e4, + 0x017bc749, + 0x03b7137a, + 0x0105ce96}, + {0x00f9218a, + 0x015b8c7c, + 0x00e102f8, + 0x0158d7e2, + 0x0169a5b8, + 0x00b2f176, + 0x018b347a, + 0x014cfef2, + 0x0214a4e3, + 0x017f1595}}, + {{0x006d7ae5, + 0x0195c371, + 0x0391e26d, + 0x0062a7c6, + 0x003f42ab, + 0x010dad86, + 0x024f8198, + 0x01542b2a, + 0x0014c454, + 0x0189c471}, + {0x0390988e, + 0x00b8799d, + 0x02e44912, + 0x0078e2e6, + 0x00075654, + 0x01923eed, + 0x0040cd72, + 0x00a37c76, + 0x0009d466, + 0x00c8531d}, + {0x02651770, + 0x00609d01, + 0x0286c265, + 0x0134513c, + 0x00ee9281, + 0x005d223c, + 0x035c760c, + 0x00679b36, + 0x0073ecb8, + 0x016faa50}}, + {{0x02c89be4, + 0x016fc244, + 0x02f38c83, + 0x018beb72, + 0x02b3ce2c, + 0x0097b065, + 0x034f017b, + 0x01dd957f, + 0x00148f61, + 0x00eab357}, + {0x0343d2f8, + 0x003398fc, + 0x011e368e, + 0x00782a1f, + 0x00019eea, + 0x00117b6f, + 0x0128d0d1, + 0x01a5e6bb, + 0x01944f1b, + 0x012b41e1}, + {0x03318301, + 0x018ecd30, + 0x0104d0b1, + 0x0038398b, + 0x03726701, + 0x019da88c, + 0x002d9769, + 0x00a7a681, + 0x031d9028, + 0x00ebfc32}}, + {{0x0220405e, + 0x0171face, + 0x02d930f8, + 0x017f6d6a, + 0x023b8c47, + 0x0129d5f9, + 0x02972456, + 0x00a3a524, + 0x006f4cd2, + 0x004439fa}, + {0x00c53505, + 0x0190c2fd, + 0x00507244, + 0x009930f9, + 0x01a39270, + 0x01d327c6, + 0x0399bc47, + 0x01cfe13d, + 0x0332bd99, + 0x00b33e7d}, + {0x0203f5e4, + 0x003627b5, + 0x00018af8, + 0x01478581, + 0x004a2218, + 0x002e3bb7, + 0x039384d0, + 0x0146ea62, + 0x020b9693, + 0x0017155f}}, + {{0x03c97e6f, + 0x00738c47, + 0x03b5db1f, + 0x01808fcf, + 0x01e8fc98, + 0x01ed25dd, + 0x01bf5045, + 0x00eb5c2b, + 0x0178fe98, + 0x01b85530}, + {0x01c20eb0, + 0x01aeec22, + 0x030b9eee, + 0x01b7d07e, + 0x0187e16f, + 0x014421fb, + 0x009fa731, + 0x0040b6d7, + 0x00841861, + 0x00a27fbc}, + {0x02d69abf, + 0x0058cdbf, + 0x0129f9ec, + 0x013c19ae, + 0x026c5b93, + 0x013a7fe7, + 0x004bb2ba, + 0x0063226f, + 0x002a95ca, + 0x01abefd9}}, + {{0x02f5d2c1, + 0x00378318, + 0x03734fb5, + 0x01258073, + 0x0263f0f6, + 0x01ad70e0, + 0x01b56d06, + 0x01188fbd, + 0x011b9503, + 0x0036d2e1}, + {0x0113a8cc, + 0x01541c3e, + 0x02ac2bbc, + 0x01d95867, + 0x01f47459, + 0x00ead489, + 0x00ab5b48, + 0x01db3b45, + 0x00edb801, + 0x004b024f}, + {0x00b8190f, + 0x011fe4c2, + 0x00621f82, + 0x010508d7, + 0x001a5a76, + 0x00c7d7fd, + 0x03aab96d, + 0x019cd9dc, + 0x019c6635, + 0x00ceaa1e}}, + {{0x01085cf2, + 0x01fd47af, + 0x03e3f5e1, + 0x004b3e99, + 0x01e3d46a, + 0x0060033c, + 0x015ff0a8, + 0x0150cdd8, + 0x029e8e21, + 0x008cf1bc}, + {0x00156cb1, + 0x003d623f, + 0x01a4f069, + 0x00d8d053, + 0x01b68aea, + 0x01ca5ab6, + 0x0316ae43, + 0x0134dc44, + 0x001c8d58, + 0x0084b343}, + {0x0318c781, + 0x0135441f, + 0x03a51a5e, + 0x019293f4, + 0x0048bb37, + 0x013d3341, + 0x0143151e, + 0x019c74e1, + 0x00911914, + 0x0076ddde}}, + {{0x006bc26f, + 0x00d48e5f, + 0x00227bbe, + 0x00629ea8, + 0x01ea5f8b, + 0x0179a330, + 0x027a1d5f, + 0x01bf8f8e, + 0x02d26e2a, + 0x00c6b65e}, + {0x01701ab6, + 0x0051da77, + 0x01b4b667, + 0x00a0ce7c, + 0x038ae37b, + 0x012ac852, + 0x03a0b0fe, + 0x0097c2bb, + 0x00a017d2, + 0x01eb8b2a}, + {0x0120b962, + 0x0005fb42, + 0x0353b6fd, + 0x0061f8ce, + 0x007a1463, + 0x01560a64, + 0x00e0a792, + 0x01907c92, + 0x013a6622, + 0x007b47f1}}}; diff --git a/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_donna_32bit_tables.h b/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_donna_32bit_tables.h new file mode 100644 index 000000000..f76a832cf --- /dev/null +++ b/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_donna_32bit_tables.h @@ -0,0 +1,17 @@ +extern const ge25519 ALIGN(16) ge25519_basepoint; + +/* + d +*/ + +extern const bignum25519 ALIGN(16) ge25519_ecd; + +extern const bignum25519 ALIGN(16) ge25519_ec2d; + +/* + sqrt(-1) +*/ + +extern const bignum25519 ALIGN(16) ge25519_sqrtneg1; + +extern const ge25519_niels ALIGN(16) ge25519_niels_sliding_multiples[32]; diff --git a/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_donna_basepoint_table.c b/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_donna_basepoint_table.c new file mode 100644 index 000000000..29d814675 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_donna_basepoint_table.c @@ -0,0 +1,1796 @@ +#include "ed25519_donna.h" + +/* multiples of the base point in packed {ysubx, xaddy, t2d} form */ +const uint8_t ALIGN(16) ge25519_niels_base_multiples[256][96] = { + {0x3e, 0x91, 0x40, 0xd7, 0x05, 0x39, 0x10, 0x9d, 0xb3, 0xbe, 0x40, 0xd1, 0x05, 0x9f, + 0x39, 0xfd, 0x09, 0x8a, 0x8f, 0x68, 0x34, 0x84, 0xc1, 0xa5, 0x67, 0x12, 0xf8, 0x98, + 0x92, 0x2f, 0xfd, 0x44, 0x85, 0x3b, 0x8c, 0xf5, 0xc6, 0x93, 0xbc, 0x2f, 0x19, 0x0e, + 0x8c, 0xfb, 0xc6, 0x2d, 0x93, 0xcf, 0xc2, 0x42, 0x3d, 0x64, 0x98, 0x48, 0x0b, 0x27, + 0x65, 0xba, 0xd4, 0x33, 0x3a, 0x9d, 0xcf, 0x07, 0x59, 0xbb, 0x6f, 0x4b, 0x67, 0x15, + 0xbd, 0xdb, 0xea, 0xa5, 0xa2, 0xee, 0x00, 0x3f, 0xe1, 0x41, 0xfa, 0xc6, 0x57, 0xc9, + 0x1c, 0x9d, 0xd4, 0xcd, 0xca, 0xec, 0x16, 0xaf, 0x1f, 0xbe, 0x0e, 0x4f}, + {0xa8, 0xd5, 0xb4, 0x42, 0x60, 0xa5, 0x99, 0x8a, 0xf6, 0xac, 0x60, 0x4e, 0x0c, 0x81, + 0x2b, 0x8f, 0xaa, 0x37, 0x6e, 0xb1, 0x6b, 0x23, 0x9e, 0xe0, 0x55, 0x25, 0xc9, 0x69, + 0xa6, 0x95, 0xb5, 0x6b, 0xd7, 0x71, 0x3c, 0x93, 0xfc, 0xe7, 0x24, 0x92, 0xb5, 0xf5, + 0x0f, 0x7a, 0x96, 0x9d, 0x46, 0x9f, 0x02, 0x07, 0xd6, 0xe1, 0x65, 0x9a, 0xa6, 0x5a, + 0x2e, 0x2e, 0x7d, 0xa8, 0x3f, 0x06, 0x0c, 0x59, 0x02, 0x68, 0xd3, 0xda, 0xaa, 0x7e, + 0x34, 0x6e, 0x05, 0x48, 0xee, 0x83, 0x93, 0x59, 0xf3, 0xba, 0x26, 0x68, 0x07, 0xe6, + 0x10, 0xbe, 0xca, 0x3b, 0xb8, 0xd1, 0x5e, 0x16, 0x0a, 0x4f, 0x31, 0x49}, + {0x65, 0xd2, 0xfc, 0xa4, 0xe8, 0x1f, 0x61, 0x56, 0x7d, 0xba, 0xc1, 0xe5, 0xfd, 0x53, + 0xd3, 0x3b, 0xbd, 0xd6, 0x4b, 0x21, 0x1a, 0xf3, 0x31, 0x81, 0x62, 0xda, 0x5b, 0x55, + 0x87, 0x15, 0xb9, 0x2a, 0x30, 0x97, 0xee, 0x4c, 0xa8, 0xb0, 0x25, 0xaf, 0x8a, 0x4b, + 0x86, 0xe8, 0x30, 0x84, 0x5a, 0x02, 0x32, 0x67, 0x01, 0x9f, 0x02, 0x50, 0x1b, 0xc1, + 0xf4, 0xf8, 0x80, 0x9a, 0x1b, 0x4e, 0x16, 0x7a, 0x34, 0x48, 0x67, 0xf1, 0xf4, 0x11, + 0xf2, 0x9b, 0x95, 0xf8, 0x2d, 0xf6, 0x17, 0x6b, 0x4e, 0xb8, 0x4e, 0x2a, 0x72, 0x5b, + 0x07, 0x6f, 0xde, 0xd7, 0x21, 0x2a, 0xbb, 0x63, 0xb9, 0x04, 0x9a, 0x54}, + {0xbf, 0x18, 0x68, 0x05, 0x0a, 0x05, 0xfe, 0x95, 0xa9, 0xfa, 0x60, 0x56, 0x71, 0x89, + 0x7e, 0x32, 0x73, 0x50, 0xa0, 0x06, 0xcd, 0xe3, 0xe8, 0xc3, 0x9a, 0xa4, 0x45, 0x74, + 0x4c, 0x3f, 0x93, 0x27, 0x9f, 0x09, 0xfc, 0x8e, 0xb9, 0x51, 0x73, 0x28, 0x38, 0x25, + 0xfd, 0x7d, 0xf4, 0xc6, 0x65, 0x67, 0x65, 0x92, 0x0a, 0xfb, 0x3d, 0x8d, 0x34, 0xca, + 0x27, 0x87, 0xe5, 0x21, 0x03, 0x91, 0x0e, 0x68, 0xb0, 0x26, 0x14, 0xe5, 0xec, 0x45, + 0x1e, 0xbf, 0x94, 0x0f, 0xba, 0x6d, 0x3d, 0xc6, 0x2b, 0xe3, 0xc0, 0x52, 0xf8, 0x8c, + 0xd5, 0x74, 0x29, 0xe4, 0x18, 0x4c, 0xe6, 0xb0, 0xb1, 0x79, 0xf0, 0x44}, + {0xba, 0xd6, 0x47, 0xa4, 0xc3, 0x82, 0x91, 0x7f, 0xb7, 0x29, 0x27, 0x4b, 0xd1, 0x14, + 0x00, 0xd5, 0x87, 0xa0, 0x64, 0xb8, 0x1c, 0xf1, 0x3c, 0xe3, 0xf3, 0x55, 0x1b, 0xeb, + 0x73, 0x7e, 0x4a, 0x15, 0x33, 0xbb, 0xa5, 0x08, 0x44, 0xbc, 0x12, 0xa2, 0x02, 0xed, + 0x5e, 0xc7, 0xc3, 0x48, 0x50, 0x8d, 0x44, 0xec, 0xbf, 0x5a, 0x0c, 0xeb, 0x1b, 0xdd, + 0xeb, 0x06, 0xe2, 0x46, 0xf1, 0xcc, 0x45, 0x29, 0xb3, 0x03, 0xd0, 0xe7, 0x79, 0xa1, + 0x32, 0xc8, 0x7e, 0x4d, 0x12, 0x00, 0x0a, 0x9d, 0x72, 0x5f, 0xf3, 0x8f, 0x6d, 0x0e, + 0xa1, 0xd4, 0xc1, 0x62, 0x98, 0x7a, 0xb2, 0x38, 0x59, 0xac, 0xb8, 0x68}, + {0xa4, 0x8c, 0x7d, 0x7b, 0xb6, 0x06, 0x98, 0x49, 0x39, 0x27, 0xd2, 0x27, 0x84, 0xe2, + 0x5b, 0x57, 0xb9, 0x53, 0x45, 0x20, 0xe7, 0x5c, 0x08, 0xbb, 0x84, 0x78, 0x41, 0xae, + 0x41, 0x4c, 0xb6, 0x38, 0x31, 0x71, 0x15, 0x77, 0xeb, 0xee, 0x0c, 0x3a, 0x88, 0xaf, + 0xc8, 0x00, 0x89, 0x15, 0x27, 0x9b, 0x36, 0xa7, 0x59, 0xda, 0x68, 0xb6, 0x65, 0x80, + 0xbd, 0x38, 0xcc, 0xa2, 0xb6, 0x7b, 0xe5, 0x51, 0xa4, 0xe3, 0x9d, 0x68, 0x91, 0xad, + 0x9d, 0x8f, 0x37, 0x91, 0xfb, 0xf8, 0x28, 0x24, 0x5f, 0x17, 0x88, 0xb9, 0xcf, 0x9f, + 0x32, 0xb5, 0x0a, 0x05, 0x9f, 0xc0, 0x54, 0x13, 0xa2, 0xdf, 0x65, 0x78}, + {0xb1, 0x21, 0x32, 0xaa, 0x9a, 0x2c, 0x6f, 0xba, 0xa7, 0x23, 0xba, 0x3b, 0x53, 0x21, + 0xa0, 0x6c, 0x3a, 0x2c, 0x19, 0x92, 0x4f, 0x76, 0xea, 0x9d, 0xe0, 0x17, 0x53, 0x2e, + 0x5d, 0xdd, 0x6e, 0x1d, 0xbf, 0xa3, 0x4e, 0x94, 0xd0, 0x5c, 0x1a, 0x6b, 0xd2, 0xc0, + 0x9d, 0xb3, 0x3a, 0x35, 0x70, 0x74, 0x49, 0x2e, 0x54, 0x28, 0x82, 0x52, 0xb2, 0x71, + 0x7e, 0x92, 0x3c, 0x28, 0x69, 0xea, 0x1b, 0x46, 0x36, 0xda, 0x0f, 0xab, 0xac, 0x8a, + 0x7a, 0x21, 0xc8, 0x49, 0x35, 0x3d, 0x54, 0xc6, 0x28, 0xa5, 0x68, 0x75, 0xab, 0x13, + 0x8b, 0x5b, 0xd0, 0x37, 0x37, 0xbc, 0x2c, 0x3a, 0x62, 0xef, 0x3c, 0x23}, + {0xd9, 0x34, 0x92, 0xf3, 0xed, 0x5d, 0xa7, 0xe2, 0xf9, 0x58, 0xb5, 0xe1, 0x80, 0x76, + 0x3d, 0x96, 0xfb, 0x23, 0x3c, 0x6e, 0xac, 0x41, 0x27, 0x2c, 0xc3, 0x01, 0x0e, 0x32, + 0xa1, 0x24, 0x90, 0x3a, 0x8f, 0x3e, 0xdd, 0x04, 0x66, 0x59, 0xb7, 0x59, 0x2c, 0x70, + 0x88, 0xe2, 0x77, 0x03, 0xb3, 0x6c, 0x23, 0xc3, 0xd9, 0x5e, 0x66, 0x9c, 0x33, 0xb1, + 0x2f, 0xe5, 0xbc, 0x61, 0x60, 0xe7, 0x15, 0x09, 0x7e, 0xa3, 0x34, 0xa8, 0x35, 0xe8, + 0x7d, 0xdf, 0xea, 0x57, 0x98, 0x68, 0xda, 0x9c, 0xe1, 0x8b, 0x26, 0xb3, 0x67, 0x71, + 0x36, 0x85, 0x11, 0x2c, 0xc2, 0xd5, 0xef, 0xdb, 0xd9, 0xb3, 0x9e, 0x58}, + {0x5e, 0x51, 0xaa, 0x49, 0x54, 0x63, 0x5b, 0xed, 0x3a, 0x82, 0xc6, 0x0b, 0x9f, 0xc4, + 0x65, 0xa8, 0xc4, 0xd1, 0x42, 0x5b, 0xe9, 0x1f, 0x0c, 0x85, 0xb9, 0x15, 0xd3, 0x03, + 0x6f, 0x6d, 0xd7, 0x30, 0x1d, 0x9c, 0x2f, 0x63, 0x0e, 0xdd, 0xcc, 0x2e, 0x15, 0x31, + 0x89, 0x76, 0x96, 0xb6, 0xd0, 0x51, 0x58, 0x7a, 0x63, 0xa8, 0x6b, 0xb7, 0xdf, 0x52, + 0x39, 0xef, 0x0e, 0xa0, 0x49, 0x7d, 0xd3, 0x6d, 0xc7, 0xe4, 0x06, 0x21, 0x17, 0x44, + 0x44, 0x6c, 0x69, 0x7f, 0x8d, 0x92, 0x80, 0xd6, 0x53, 0xfb, 0x26, 0x3f, 0x4d, 0x69, + 0xa4, 0x9e, 0x73, 0xb4, 0xb0, 0x4b, 0x86, 0x2e, 0x11, 0x97, 0xc6, 0x10}, + {0xde, 0x5f, 0xbe, 0x7d, 0x27, 0xc4, 0x93, 0x64, 0xa2, 0x7e, 0xad, 0x19, 0xad, 0x4f, + 0x5d, 0x26, 0x90, 0x45, 0x30, 0x46, 0xc8, 0xdf, 0x00, 0x0e, 0x09, 0xfe, 0x66, 0xed, + 0xab, 0x1c, 0xe6, 0x25, 0x05, 0xc8, 0x58, 0x83, 0xa0, 0x2a, 0xa6, 0x0c, 0x47, 0x42, + 0x20, 0x7a, 0xe3, 0x4a, 0x3d, 0x6a, 0xdc, 0xed, 0x11, 0x3b, 0xa6, 0xd3, 0x64, 0x74, + 0xef, 0x06, 0x08, 0x55, 0xaf, 0x9b, 0xbf, 0x03, 0x04, 0x66, 0x58, 0xcc, 0x28, 0xe1, + 0x13, 0x3f, 0x7e, 0x74, 0x59, 0xb4, 0xec, 0x73, 0x58, 0x6f, 0xf5, 0x68, 0x12, 0xcc, + 0xed, 0x3d, 0xb6, 0xa0, 0x2c, 0xe2, 0x86, 0x45, 0x63, 0x78, 0x6d, 0x56}, + {0x34, 0x08, 0xc1, 0x9c, 0x9f, 0xa4, 0x37, 0x16, 0x51, 0xc4, 0x9b, 0xa8, 0xd5, 0x56, + 0x8e, 0xbc, 0xdb, 0xd2, 0x7f, 0x7f, 0x0f, 0xec, 0xb5, 0x1c, 0xd9, 0x35, 0xcc, 0x5e, + 0xca, 0x5b, 0x97, 0x33, 0xd0, 0x2f, 0x5a, 0xc6, 0x85, 0x42, 0x05, 0xa1, 0xc3, 0x67, + 0x16, 0xf3, 0x2a, 0x11, 0x64, 0x6c, 0x58, 0xee, 0x1a, 0x73, 0x40, 0xe2, 0x0a, 0x68, + 0x2a, 0xb2, 0x93, 0x47, 0xf3, 0xa5, 0xfb, 0x14, 0xd4, 0xf7, 0x85, 0x69, 0x16, 0x46, + 0xd7, 0x3c, 0x57, 0x00, 0xc8, 0xc9, 0x84, 0x5e, 0x3e, 0x59, 0x1e, 0x13, 0x61, 0x7b, + 0xb6, 0xf2, 0xc3, 0x2f, 0x6c, 0x52, 0xfc, 0x83, 0xea, 0x9c, 0x82, 0x14}, + {0xc2, 0x95, 0xdd, 0x97, 0x84, 0x7b, 0x43, 0xff, 0xa7, 0xb5, 0x4e, 0xaa, 0x30, 0x4e, + 0x74, 0x6c, 0x8b, 0xe8, 0x85, 0x3c, 0x61, 0x5d, 0x0c, 0x9e, 0x73, 0x81, 0x75, 0x5f, + 0x1e, 0xc7, 0xd9, 0x2f, 0xb8, 0xec, 0x71, 0x4e, 0x2f, 0x0b, 0xe7, 0x21, 0xe3, 0x77, + 0xa4, 0x40, 0xb9, 0xdd, 0x56, 0xe6, 0x80, 0x4f, 0x1d, 0xce, 0xce, 0x56, 0x65, 0xbf, + 0x7e, 0x7b, 0x5d, 0x53, 0xc4, 0x3b, 0xfc, 0x05, 0xdd, 0xde, 0xaf, 0x52, 0xae, 0xb3, + 0xb8, 0x24, 0xcf, 0x30, 0x3b, 0xed, 0x8c, 0x63, 0x95, 0x34, 0x95, 0x81, 0xbe, 0xa9, + 0x83, 0xbc, 0xa4, 0x33, 0x04, 0x1f, 0x65, 0x5c, 0x47, 0x67, 0x37, 0x37}, + {0xd9, 0xad, 0xd1, 0x40, 0xfd, 0x99, 0xba, 0x2f, 0x27, 0xd0, 0xf4, 0x96, 0x6f, 0x16, + 0x07, 0xb3, 0xae, 0x3b, 0xf0, 0x15, 0x52, 0xf0, 0x63, 0x43, 0x99, 0xf9, 0x18, 0x3b, + 0x6c, 0xa5, 0xbe, 0x1f, 0x90, 0x65, 0x24, 0x14, 0xcb, 0x95, 0x40, 0x63, 0x35, 0x55, + 0xc1, 0x16, 0x40, 0x14, 0x12, 0xef, 0x60, 0xbc, 0x10, 0x89, 0x0c, 0x14, 0x38, 0x9e, + 0x8c, 0x7c, 0x90, 0x30, 0x57, 0x90, 0xf5, 0x6b, 0x8a, 0x5b, 0x41, 0xe1, 0xf1, 0x78, + 0xa7, 0x0f, 0x7e, 0xa7, 0xc3, 0xba, 0xf7, 0x9f, 0x40, 0x06, 0x50, 0x9a, 0xa2, 0x9a, + 0xb8, 0xd7, 0x52, 0x6f, 0x56, 0x5a, 0x63, 0x7a, 0xf6, 0x1c, 0x52, 0x02}, + {0x94, 0x52, 0x9d, 0x0a, 0x0b, 0xee, 0x3f, 0x51, 0x66, 0x5a, 0xdf, 0x0f, 0x5c, 0xe7, + 0x98, 0x8f, 0xce, 0x07, 0xe1, 0xbf, 0x88, 0x86, 0x61, 0xd4, 0xed, 0x2c, 0x38, 0x71, + 0x7e, 0x0a, 0xa0, 0x3f, 0xe4, 0x5e, 0x2f, 0x77, 0x20, 0x67, 0x14, 0xb1, 0xce, 0x9a, + 0x07, 0x96, 0xb1, 0x94, 0xf8, 0xe8, 0x4a, 0x82, 0xac, 0x00, 0x4d, 0x22, 0xf8, 0x4a, + 0xc4, 0x6c, 0xcd, 0xf7, 0xd9, 0x53, 0x17, 0x00, 0x34, 0xdb, 0x3d, 0x96, 0x2d, 0x23, + 0x69, 0x3c, 0x58, 0x38, 0x97, 0xb4, 0xda, 0x87, 0xde, 0x1d, 0x85, 0xf2, 0x91, 0xa0, + 0xf9, 0xd1, 0xd7, 0xaa, 0xb6, 0xed, 0x48, 0xa0, 0x2f, 0xfe, 0xb5, 0x12}, + {0x4d, 0xe3, 0xfc, 0x96, 0xc4, 0xfb, 0xf0, 0x71, 0xed, 0x5b, 0xf3, 0xad, 0x6b, 0x82, + 0xb9, 0x73, 0x61, 0xc5, 0x28, 0xff, 0x61, 0x72, 0x04, 0xd2, 0x6f, 0x20, 0xb1, 0x6f, + 0xf9, 0x76, 0x9b, 0x74, 0x92, 0x1e, 0x6f, 0xad, 0x26, 0x7c, 0x2b, 0xdf, 0x13, 0x89, + 0x4b, 0x50, 0x23, 0xd3, 0x66, 0x4b, 0xc3, 0x8b, 0x1c, 0x75, 0xc0, 0x9d, 0x40, 0x8c, + 0xb8, 0xc7, 0x96, 0x07, 0xc2, 0x93, 0x7e, 0x6f, 0x05, 0xae, 0xa6, 0xae, 0x04, 0xf6, + 0x5a, 0x1f, 0x99, 0x9c, 0xe4, 0xbe, 0xf1, 0x51, 0x23, 0xc1, 0x66, 0x6b, 0xff, 0xee, + 0xb5, 0x08, 0xa8, 0x61, 0x51, 0x21, 0xe0, 0x01, 0x0f, 0xc1, 0xce, 0x0f}, + {0x44, 0x1e, 0xfe, 0x49, 0xa6, 0x58, 0x4d, 0x64, 0x7e, 0x77, 0xad, 0x31, 0xa2, 0xae, + 0xfc, 0x21, 0xd2, 0xd0, 0x7f, 0x88, 0x5a, 0x1c, 0x44, 0x02, 0xf3, 0x11, 0xc5, 0x83, + 0x71, 0xaa, 0x01, 0x49, 0x45, 0x4e, 0x24, 0xc4, 0x9d, 0xd2, 0xf2, 0x3d, 0x0a, 0xde, + 0xd8, 0x93, 0x74, 0x0e, 0x02, 0x2b, 0x4d, 0x21, 0x0c, 0x82, 0x7e, 0x06, 0xc8, 0x6c, + 0x0a, 0xb9, 0xea, 0x6f, 0x16, 0x79, 0x37, 0x41, 0xf0, 0xf8, 0x1a, 0x8c, 0x54, 0xb7, + 0xb1, 0x08, 0xb4, 0x99, 0x62, 0x24, 0x7c, 0x7a, 0x0f, 0xce, 0x39, 0xd9, 0x06, 0x1e, + 0xf9, 0xb0, 0x60, 0xf7, 0x13, 0x12, 0x6d, 0x72, 0x7b, 0x88, 0xbb, 0x41}, + {0xbe, 0x46, 0x43, 0x74, 0x44, 0x7d, 0xe8, 0x40, 0x25, 0x2b, 0xb5, 0x15, 0xd4, 0xda, + 0x48, 0x1d, 0x3e, 0x60, 0x3b, 0xa1, 0x18, 0x8a, 0x3a, 0x7c, 0xf7, 0xbd, 0xcd, 0x2f, + 0xc1, 0x28, 0xb7, 0x4e, 0xae, 0x91, 0x66, 0x7c, 0x59, 0x4c, 0x23, 0x7e, 0xc8, 0xb4, + 0x85, 0x0a, 0x3d, 0x9d, 0x88, 0x64, 0xe7, 0xfa, 0x4a, 0x35, 0x0c, 0xc9, 0xe2, 0xda, + 0x1d, 0x9e, 0x6a, 0x0c, 0x07, 0x1e, 0x87, 0x0a, 0x89, 0x89, 0xbc, 0x4b, 0x99, 0xb5, + 0x01, 0x33, 0x60, 0x42, 0xdd, 0x5b, 0x3a, 0xae, 0x6b, 0x73, 0x3c, 0x9e, 0xd5, 0x19, + 0xe2, 0xad, 0x61, 0x0d, 0x64, 0xd4, 0x85, 0x26, 0x0f, 0x30, 0xe7, 0x3e}, + {0xb7, 0xd6, 0x7d, 0x9e, 0xe4, 0x55, 0xd2, 0xf5, 0xac, 0x1e, 0x0b, 0x61, 0x5c, 0x11, + 0x16, 0x80, 0xca, 0x87, 0xe1, 0x92, 0x5d, 0x97, 0x99, 0x3c, 0xc2, 0x25, 0x91, 0x97, + 0x62, 0x57, 0x81, 0x13, 0x18, 0x75, 0x1e, 0x84, 0x47, 0x79, 0xfa, 0x43, 0xd7, 0x46, + 0x9c, 0x63, 0x59, 0xfa, 0xc6, 0xe5, 0x74, 0x2b, 0x05, 0xe3, 0x1d, 0x5e, 0x06, 0xa1, + 0x30, 0x90, 0xb8, 0xcf, 0xa2, 0xc6, 0x47, 0x7d, 0xe0, 0xd6, 0xf0, 0x8e, 0x14, 0xd0, + 0xda, 0x3f, 0x3c, 0x6f, 0x54, 0x91, 0x9a, 0x74, 0x3e, 0x9d, 0x57, 0x81, 0xbb, 0x26, + 0x10, 0x62, 0xec, 0x71, 0x80, 0xec, 0xc9, 0x34, 0x8d, 0xf5, 0x8c, 0x14}, + {0x27, 0xf0, 0x34, 0x79, 0xf6, 0x92, 0xa4, 0x46, 0xa9, 0x0a, 0x84, 0xf6, 0xbe, 0x84, + 0x99, 0x46, 0x54, 0x18, 0x61, 0x89, 0x2a, 0xbc, 0xa1, 0x5c, 0xd4, 0xbb, 0x5d, 0xbd, + 0x1e, 0xfa, 0xf2, 0x3f, 0x6d, 0x75, 0xe4, 0x9a, 0x7d, 0x2f, 0x57, 0xe2, 0x7f, 0x48, + 0xf3, 0x88, 0xbb, 0x45, 0xc3, 0x56, 0x8d, 0xa8, 0x60, 0x69, 0x6d, 0x0b, 0xd1, 0x9f, + 0xb9, 0xa1, 0xae, 0x4e, 0xad, 0xeb, 0x8f, 0x27, 0x66, 0x39, 0x93, 0x8c, 0x1f, 0x68, + 0xaa, 0xb1, 0x98, 0x0c, 0x29, 0x20, 0x9c, 0x94, 0x21, 0x8c, 0x52, 0x3c, 0x9d, 0x21, + 0x91, 0x52, 0x11, 0x39, 0x7b, 0x67, 0x9c, 0xfe, 0x02, 0xdd, 0x04, 0x41}, + {0x2a, 0x42, 0x24, 0x11, 0x5e, 0xbf, 0xb2, 0x72, 0xb5, 0x3a, 0xa3, 0x98, 0x33, 0x0c, + 0xfa, 0xa1, 0x66, 0xb6, 0x52, 0xfa, 0x01, 0x61, 0xcb, 0x94, 0xd5, 0x53, 0xaf, 0xaf, + 0x00, 0x3b, 0x86, 0x2c, 0xb8, 0x6a, 0x09, 0xdb, 0x06, 0x4e, 0x21, 0x81, 0x35, 0x4f, + 0xe4, 0x0c, 0xc9, 0xb6, 0xa8, 0x21, 0xf5, 0x2a, 0x9e, 0x40, 0x2a, 0xc1, 0x24, 0x65, + 0x81, 0xa4, 0xfc, 0x8e, 0xa4, 0xb5, 0x65, 0x01, 0x76, 0x6a, 0x84, 0xa0, 0x74, 0xa4, + 0x90, 0xf1, 0xc0, 0x7c, 0x2f, 0xcd, 0x84, 0xf9, 0xef, 0x12, 0x8f, 0x2b, 0xaa, 0x58, + 0x06, 0x29, 0x5e, 0x69, 0xb8, 0xc8, 0xfe, 0xbf, 0xd9, 0x67, 0x1b, 0x59}, + {0xfa, 0x9b, 0xb4, 0x80, 0x1c, 0x0d, 0x2f, 0x31, 0x8a, 0xec, 0xf3, 0xab, 0x5e, 0x51, + 0x79, 0x59, 0x88, 0x1c, 0xf0, 0x9e, 0xc0, 0x33, 0x70, 0x72, 0xcb, 0x7b, 0x8f, 0xca, + 0xc7, 0x2e, 0xe0, 0x3d, 0x5d, 0xb5, 0x18, 0x9f, 0x71, 0xb3, 0xb9, 0x99, 0x1e, 0x64, + 0x8c, 0xa1, 0xfa, 0xe5, 0x65, 0xe4, 0xed, 0x05, 0x9f, 0xc2, 0x36, 0x11, 0x08, 0x61, + 0x8b, 0x12, 0x30, 0x70, 0x86, 0x4f, 0x9b, 0x48, 0xef, 0x92, 0xeb, 0x3a, 0x2d, 0x10, + 0x32, 0xd2, 0x61, 0xa8, 0x16, 0x61, 0xb4, 0x53, 0x62, 0xe1, 0x24, 0xaa, 0x0b, 0x19, + 0xe7, 0xab, 0x7e, 0x3d, 0xbf, 0xbe, 0x6c, 0x49, 0xba, 0xfb, 0xf5, 0x49}, + {0xd4, 0xcf, 0x5b, 0x8a, 0x10, 0x9a, 0x94, 0x30, 0xeb, 0x73, 0x64, 0xbc, 0x70, 0xdd, + 0x40, 0xdc, 0x1c, 0x0d, 0x7c, 0x30, 0xc1, 0x94, 0xc2, 0x92, 0x74, 0x6e, 0xfa, 0xcb, + 0x6d, 0xa8, 0x04, 0x56, 0x2e, 0x57, 0x9c, 0x1e, 0x8c, 0x62, 0x5d, 0x15, 0x41, 0x47, + 0x88, 0xc5, 0xac, 0x86, 0x4d, 0x8a, 0xeb, 0x63, 0x57, 0x51, 0xf6, 0x52, 0xa3, 0x91, + 0x5b, 0x51, 0x67, 0x88, 0xc2, 0xa6, 0xa1, 0x06, 0xb6, 0x64, 0x17, 0x7c, 0xd4, 0xd1, + 0x88, 0x72, 0x51, 0x8b, 0x41, 0xe0, 0x40, 0x11, 0x54, 0x72, 0xd1, 0xf6, 0xac, 0x18, + 0x60, 0x1a, 0x03, 0x9f, 0xc6, 0x42, 0x27, 0xfe, 0x89, 0x9e, 0x98, 0x20}, + {0x7f, 0xcc, 0x2d, 0x3a, 0xfd, 0x77, 0x97, 0x49, 0x92, 0xd8, 0x4f, 0xa5, 0x2c, 0x7c, + 0x85, 0x32, 0xa0, 0xe3, 0x07, 0xd2, 0x64, 0xd8, 0x79, 0xa2, 0x29, 0x7e, 0xa6, 0x0c, + 0x1d, 0xed, 0x03, 0x04, 0x2e, 0xec, 0xea, 0x85, 0x8b, 0x27, 0x74, 0x16, 0xdf, 0x2b, + 0xcb, 0x7a, 0x07, 0xdc, 0x21, 0x56, 0x5a, 0xf4, 0xcb, 0x61, 0x16, 0x4c, 0x0a, 0x64, + 0xd3, 0x95, 0x05, 0xf7, 0x50, 0x99, 0x0b, 0x73, 0x52, 0xc5, 0x4e, 0x87, 0x35, 0x2d, + 0x4b, 0xc9, 0x8d, 0x6f, 0x24, 0x98, 0xcf, 0xc8, 0xe6, 0xc5, 0xce, 0x35, 0xc0, 0x16, + 0xfa, 0x46, 0xcb, 0xf7, 0xcc, 0x3d, 0x30, 0x08, 0x43, 0x45, 0xd7, 0x5b}, + {0xc2, 0x4c, 0xb2, 0x28, 0x95, 0xd1, 0x9a, 0x7f, 0x81, 0xc1, 0x35, 0x63, 0x65, 0x54, + 0x6b, 0x7f, 0x36, 0x72, 0xc0, 0x4f, 0x6e, 0xb6, 0xb8, 0x66, 0x83, 0xad, 0x80, 0x73, + 0x00, 0x78, 0x3a, 0x13, 0x2a, 0x79, 0xe7, 0x15, 0x21, 0x93, 0xc4, 0x85, 0xc9, 0xdd, + 0xcd, 0xbd, 0xa2, 0x89, 0x4c, 0xc6, 0x62, 0xd7, 0xa3, 0xad, 0xa8, 0x3d, 0x1e, 0x9d, + 0x2c, 0xf8, 0x67, 0x30, 0x12, 0xdb, 0xb7, 0x5b, 0xbe, 0x62, 0xca, 0xc6, 0x67, 0xf4, + 0x61, 0x09, 0xee, 0x52, 0x19, 0x21, 0xd6, 0x21, 0xec, 0x04, 0x70, 0x47, 0xd5, 0x9b, + 0x77, 0x60, 0x23, 0x18, 0xd2, 0xe0, 0xf0, 0x58, 0x6d, 0xca, 0x0d, 0x74}, + {0x4e, 0xce, 0xcf, 0x52, 0x07, 0xee, 0x48, 0xdf, 0xb7, 0x08, 0xec, 0x06, 0xf3, 0xfa, + 0xff, 0xc3, 0xc4, 0x59, 0x54, 0xb9, 0x2a, 0x0b, 0x71, 0x05, 0x8d, 0xa3, 0x3e, 0x96, + 0xfa, 0x25, 0x1d, 0x16, 0x3c, 0x43, 0x78, 0x04, 0x57, 0x8c, 0x1a, 0x23, 0x9d, 0x43, + 0x81, 0xc2, 0x0e, 0x27, 0xb5, 0xb7, 0x9f, 0x07, 0xd9, 0xe3, 0xea, 0x99, 0xaa, 0xdb, + 0xd9, 0x03, 0x2b, 0x6c, 0x25, 0xf5, 0x03, 0x2c, 0x7d, 0xa4, 0x53, 0x7b, 0x75, 0x18, + 0x0f, 0x79, 0x79, 0x58, 0x0c, 0xcf, 0x30, 0x01, 0x7b, 0x30, 0xf9, 0xf7, 0x7e, 0x25, + 0x77, 0x3d, 0x90, 0x31, 0xaf, 0xbb, 0x96, 0xbd, 0xbd, 0x68, 0x94, 0x69}, + {0xcf, 0xfe, 0xda, 0xf4, 0x46, 0x2f, 0x1f, 0xbd, 0xf7, 0xd6, 0x7f, 0xa4, 0x14, 0x01, + 0xef, 0x7c, 0x7f, 0xb3, 0x47, 0x4a, 0xda, 0xfd, 0x1f, 0xd3, 0x85, 0x57, 0x90, 0x73, + 0xa4, 0x19, 0x52, 0x52, 0x48, 0x19, 0xa9, 0x6a, 0xe6, 0x3d, 0xdd, 0xd8, 0xcc, 0xd2, + 0xc0, 0x2f, 0xc2, 0x64, 0x50, 0x48, 0x2f, 0xea, 0xfd, 0x34, 0x66, 0x24, 0x48, 0x9b, + 0x3a, 0x2e, 0x4a, 0x6c, 0x4e, 0x1c, 0x3e, 0x29, 0xe1, 0x12, 0x51, 0x92, 0x4b, 0x13, + 0x6e, 0x37, 0xa0, 0x5d, 0xa1, 0xdc, 0xb5, 0x78, 0x37, 0x70, 0x11, 0x31, 0x1c, 0x46, + 0xaf, 0x89, 0x45, 0xb0, 0x23, 0x28, 0x03, 0x7f, 0x44, 0x5c, 0x60, 0x5b}, + {0x89, 0x7c, 0xc4, 0x20, 0x59, 0x80, 0x65, 0xb9, 0xcc, 0x8f, 0x3b, 0x92, 0x0c, 0x10, + 0xf0, 0xe7, 0x77, 0xef, 0xe2, 0x02, 0x65, 0x25, 0x01, 0x00, 0xee, 0xb3, 0xae, 0xa8, + 0xce, 0x6d, 0xa7, 0x24, 0x4c, 0xf0, 0xe7, 0xf0, 0xc6, 0xfe, 0xe9, 0x3b, 0x62, 0x49, + 0xe3, 0x75, 0x9e, 0x57, 0x6a, 0x86, 0x1a, 0xe6, 0x1d, 0x1e, 0x16, 0xef, 0x42, 0x55, + 0xd5, 0xbd, 0x5a, 0xcc, 0xf4, 0xfe, 0x12, 0x2f, 0x40, 0xc7, 0xc0, 0xdf, 0xb2, 0x22, + 0x45, 0x0a, 0x07, 0xa4, 0xc9, 0x40, 0x7f, 0x6e, 0xd0, 0x10, 0x68, 0xf6, 0xcf, 0x78, + 0x41, 0x14, 0xcf, 0xc6, 0x90, 0x37, 0xa4, 0x18, 0x25, 0x7b, 0x60, 0x5e}, + {0x18, 0x18, 0xdf, 0x6c, 0x8f, 0x1d, 0xb3, 0x58, 0xa2, 0x58, 0x62, 0xc3, 0x4f, 0xa7, + 0xcf, 0x35, 0x6e, 0x1d, 0xe6, 0x66, 0x4f, 0xff, 0xb3, 0xe1, 0xf7, 0xd5, 0xcd, 0x6c, + 0xab, 0xac, 0x67, 0x50, 0x14, 0xcf, 0x96, 0xa5, 0x1c, 0x43, 0x2c, 0xa0, 0x00, 0xe4, + 0xd3, 0xae, 0x40, 0x2d, 0xc4, 0xe3, 0xdb, 0x26, 0x0f, 0x2e, 0x80, 0x26, 0x45, 0xd2, + 0x68, 0x70, 0x45, 0x9e, 0x13, 0x33, 0x1f, 0x20, 0x51, 0x9d, 0x03, 0x08, 0x6b, 0x7f, + 0x52, 0xfd, 0x06, 0x00, 0x7c, 0x01, 0x64, 0x49, 0xb1, 0x18, 0xa8, 0xa4, 0x25, 0x2e, + 0xb0, 0x0e, 0x22, 0xd5, 0x75, 0x03, 0x46, 0x62, 0x88, 0xba, 0x7c, 0x39}, + {0xb2, 0x59, 0x59, 0xf0, 0x93, 0x30, 0xc1, 0x30, 0x76, 0x79, 0xa9, 0xe9, 0x8d, 0xa1, + 0x3a, 0xe2, 0x26, 0x5e, 0x1d, 0x72, 0x91, 0xd4, 0x2f, 0x22, 0x3a, 0x6c, 0x6e, 0x76, + 0x20, 0xd3, 0x39, 0x23, 0xe7, 0x79, 0x13, 0xc8, 0xfb, 0xc3, 0x15, 0x78, 0xf1, 0x2a, + 0xe1, 0xdd, 0x20, 0x94, 0x61, 0xa6, 0xd5, 0xfd, 0xa8, 0x85, 0xf8, 0xc0, 0xa9, 0xff, + 0x52, 0xc2, 0xe1, 0xc1, 0x22, 0x40, 0x1b, 0x77, 0xa7, 0x2f, 0x3a, 0x51, 0x86, 0xd9, + 0x7d, 0xd8, 0x08, 0xcf, 0xd4, 0xf9, 0x71, 0x9b, 0xac, 0xf5, 0xb3, 0x83, 0xa2, 0x1e, + 0x1b, 0xc3, 0x6b, 0xd0, 0x76, 0x1a, 0x97, 0x19, 0x92, 0x18, 0x1a, 0x33}, + {0xc6, 0x80, 0x4f, 0xfb, 0x45, 0x6f, 0x16, 0xf5, 0xcf, 0x75, 0xc7, 0x61, 0xde, 0xc7, + 0x36, 0x9c, 0x1c, 0xd9, 0x41, 0x90, 0x1b, 0xe8, 0xd4, 0xe3, 0x21, 0xfe, 0xbd, 0x83, + 0x6b, 0x7c, 0x16, 0x31, 0xaf, 0x72, 0x75, 0x9d, 0x3a, 0x2f, 0x51, 0x26, 0x9e, 0x4a, + 0x07, 0x68, 0x88, 0xe2, 0xcb, 0x5b, 0xc4, 0xf7, 0x80, 0x11, 0xc1, 0xc1, 0xed, 0x84, + 0x7b, 0xa6, 0x49, 0xf6, 0x9f, 0x61, 0xc9, 0x1a, 0x68, 0x10, 0x4b, 0x52, 0x42, 0x38, + 0x2b, 0xf2, 0x87, 0xe9, 0x9c, 0xee, 0x3b, 0x34, 0x68, 0x50, 0xc8, 0x50, 0x62, 0x4a, + 0x84, 0x71, 0x9d, 0xfc, 0x11, 0xb1, 0x08, 0x1f, 0x34, 0x36, 0x24, 0x61}, + {0x8d, 0x89, 0x4e, 0x87, 0xdb, 0x41, 0x9d, 0xd9, 0x20, 0xdc, 0x07, 0x6c, 0xf1, 0xa5, + 0xfe, 0x09, 0xbc, 0x9b, 0x0f, 0xd0, 0x67, 0x2c, 0x3d, 0x79, 0x40, 0xff, 0x5e, 0x9e, + 0x30, 0xe2, 0xeb, 0x46, 0x38, 0x26, 0x2d, 0x1a, 0xe3, 0x49, 0x63, 0x8b, 0x35, 0xfd, + 0xd3, 0x9b, 0x00, 0xb7, 0xdf, 0x9d, 0xa4, 0x6b, 0xa0, 0xa3, 0xb8, 0xf1, 0x8b, 0x7f, + 0x45, 0x04, 0xd9, 0x78, 0x31, 0xaa, 0x22, 0x15, 0x38, 0x49, 0x61, 0x69, 0x53, 0x2f, + 0x38, 0x2c, 0x10, 0x6d, 0x2d, 0xb7, 0x9a, 0x40, 0xfe, 0xda, 0x27, 0xf2, 0x46, 0xb6, + 0x91, 0x33, 0xc8, 0xe8, 0x6c, 0x30, 0x24, 0x05, 0xf5, 0x70, 0xfe, 0x45}, + {0x8c, 0x0b, 0x0c, 0x96, 0xa6, 0x75, 0x48, 0xda, 0x20, 0x2f, 0x0e, 0xef, 0x76, 0xd0, + 0x68, 0x5b, 0xd4, 0x8f, 0x0b, 0x3d, 0xcf, 0x51, 0xfb, 0x07, 0xd4, 0x92, 0xe3, 0xa0, + 0x23, 0x16, 0x8d, 0x42, 0x91, 0x14, 0x95, 0xc8, 0x20, 0x49, 0xf2, 0x62, 0xa2, 0x0c, + 0x63, 0x3f, 0xc8, 0x07, 0xf0, 0x05, 0xb8, 0xd4, 0xc9, 0xf5, 0xd2, 0x45, 0xbb, 0x6f, + 0x45, 0x22, 0x7a, 0xb5, 0x6d, 0x9f, 0x61, 0x16, 0xfd, 0x08, 0xa3, 0x01, 0x44, 0x4a, + 0x4f, 0x08, 0xac, 0xca, 0xa5, 0x76, 0xc3, 0x19, 0x22, 0xa8, 0x7d, 0xbc, 0xd1, 0x43, + 0x46, 0xde, 0xb8, 0xde, 0xc6, 0x38, 0xbd, 0x60, 0x2d, 0x59, 0x81, 0x1d}, + {0x5f, 0xac, 0x0d, 0xa6, 0x56, 0x87, 0x36, 0x61, 0x57, 0xdc, 0xab, 0xeb, 0x6a, 0x2f, + 0xe0, 0x17, 0x7d, 0x0f, 0xce, 0x4c, 0x2d, 0x3f, 0x19, 0x7f, 0xf0, 0xdc, 0xec, 0x89, + 0x77, 0x4a, 0x23, 0x20, 0xe8, 0xc5, 0x85, 0x7b, 0x9f, 0xb6, 0x65, 0x87, 0xb2, 0xba, + 0x68, 0xd1, 0x8b, 0x67, 0xf0, 0x6f, 0x9b, 0x0f, 0x33, 0x1d, 0x7c, 0xe7, 0x70, 0x3a, + 0x7c, 0x8e, 0xaf, 0xb0, 0x51, 0x6d, 0x5f, 0x3a, 0x52, 0xb2, 0x78, 0x71, 0xb6, 0x0d, + 0xd2, 0x76, 0x60, 0xd1, 0x1e, 0xd5, 0xf9, 0x34, 0x1c, 0x07, 0x70, 0x11, 0xe4, 0xb3, + 0x20, 0x4a, 0x2a, 0xf6, 0x66, 0xe3, 0xff, 0x3c, 0x35, 0x82, 0xd6, 0x7c}, + {0xb6, 0xfa, 0x87, 0xd8, 0x5b, 0xa4, 0xe1, 0x0b, 0x6e, 0x3b, 0x40, 0xba, 0x32, 0x6a, + 0x84, 0x2a, 0x00, 0x60, 0x6e, 0xe9, 0x12, 0x10, 0x92, 0xd9, 0x43, 0x09, 0xdc, 0x3b, + 0x86, 0xc8, 0x38, 0x28, 0xf3, 0xf4, 0xac, 0x68, 0x60, 0xcd, 0x65, 0xa6, 0xd3, 0xe3, + 0xd7, 0x3c, 0x18, 0x2d, 0xd9, 0x42, 0xd9, 0x25, 0x60, 0x33, 0x9d, 0x38, 0x59, 0x57, + 0xff, 0xd8, 0x2c, 0x2b, 0x3b, 0x25, 0xf0, 0x3e, 0x30, 0x50, 0x46, 0x4a, 0xcf, 0xb0, + 0x6b, 0xd1, 0xab, 0x77, 0xc5, 0x15, 0x41, 0x6b, 0x49, 0xfa, 0x9d, 0x41, 0xab, 0xf4, + 0x8a, 0xae, 0xcf, 0x82, 0x12, 0x28, 0xa8, 0x06, 0xa6, 0xb8, 0xdc, 0x21}, + {0xc8, 0x9f, 0x9d, 0x8c, 0x46, 0x04, 0x60, 0x5c, 0xcb, 0xa3, 0x2a, 0xd4, 0x6e, 0x09, + 0x40, 0x25, 0x9c, 0x2f, 0xee, 0x12, 0x4c, 0x4d, 0x5b, 0x12, 0xab, 0x1d, 0xa3, 0x94, + 0x81, 0xd0, 0xc3, 0x0b, 0xba, 0x31, 0x77, 0xbe, 0xfa, 0x00, 0x8d, 0x9a, 0x89, 0x18, + 0x9e, 0x62, 0x7e, 0x60, 0x03, 0x82, 0x7f, 0xd9, 0xf3, 0x43, 0x37, 0x02, 0xcc, 0xb2, + 0x8b, 0x67, 0x6f, 0x6c, 0xbf, 0x0d, 0x84, 0x5d, 0x8b, 0xe1, 0x9f, 0x30, 0x0d, 0x38, + 0x6e, 0x70, 0xc7, 0x65, 0xe1, 0xb9, 0xa6, 0x2d, 0xb0, 0x6e, 0xab, 0x20, 0xae, 0x7d, + 0x99, 0xba, 0xbb, 0x57, 0xdd, 0x96, 0xc1, 0x2a, 0x23, 0x76, 0x42, 0x3a}, + {0xfa, 0x84, 0x70, 0x8a, 0x2c, 0x43, 0x42, 0x4b, 0x45, 0xe5, 0xb9, 0xdf, 0xe3, 0x19, + 0x8a, 0x89, 0x5d, 0xe4, 0x58, 0x9c, 0x21, 0x00, 0x9f, 0xbe, 0xd1, 0xeb, 0x6d, 0xa1, + 0xce, 0x77, 0xf1, 0x1f, 0xcb, 0x7e, 0x44, 0xdb, 0x72, 0xc1, 0xf8, 0x3b, 0xbd, 0x2d, + 0x28, 0xc6, 0x1f, 0xc4, 0xcf, 0x5f, 0xfe, 0x15, 0xaa, 0x75, 0xc0, 0xff, 0xac, 0x80, + 0xf9, 0xa9, 0xe1, 0x24, 0xe8, 0xc9, 0x70, 0x07, 0xfd, 0xb5, 0xb5, 0x45, 0x9a, 0xd9, + 0x61, 0xcf, 0x24, 0x79, 0x3a, 0x1b, 0xe9, 0x84, 0x09, 0x86, 0x89, 0x3e, 0x3e, 0x30, + 0x19, 0x09, 0x30, 0xe7, 0x1e, 0x0b, 0x50, 0x41, 0xfd, 0x64, 0xf2, 0x39}, + {0x9c, 0xe2, 0xe7, 0xdb, 0x17, 0x34, 0xad, 0xa7, 0x9c, 0x13, 0x9c, 0x2b, 0x6a, 0x37, + 0x94, 0xbd, 0xa9, 0x7b, 0x59, 0x93, 0x8e, 0x1b, 0xe9, 0xa0, 0x40, 0x98, 0x88, 0x68, + 0x34, 0xd7, 0x12, 0x17, 0xe1, 0x7b, 0x09, 0xfe, 0xab, 0x4a, 0x9b, 0xd1, 0x29, 0x19, + 0xe0, 0xdf, 0xe1, 0xfc, 0x6d, 0xa4, 0xff, 0xf1, 0xa6, 0x2c, 0x94, 0x08, 0xc9, 0xc3, + 0x4e, 0xf1, 0x35, 0x2c, 0x27, 0x21, 0xc6, 0x65, 0xdd, 0x93, 0x31, 0xce, 0xf8, 0x89, + 0x2b, 0xe7, 0xbb, 0xc0, 0x25, 0xa1, 0x56, 0x33, 0x10, 0x4d, 0x83, 0xfe, 0x1c, 0x2e, + 0x3d, 0xa9, 0x19, 0x04, 0x72, 0xe2, 0x9c, 0xb1, 0x0a, 0x80, 0xf9, 0x22}, + {0xcb, 0xf8, 0x9e, 0x3e, 0x8a, 0x36, 0x5a, 0x60, 0x15, 0x47, 0x50, 0xa5, 0x22, 0xc0, + 0xe9, 0xe3, 0x8f, 0x24, 0x24, 0x5f, 0xb0, 0x48, 0x3d, 0x55, 0xe5, 0x26, 0x76, 0x64, + 0xcd, 0x16, 0xf4, 0x13, 0xac, 0xfd, 0x6e, 0x9a, 0xdd, 0x9f, 0x02, 0x42, 0x41, 0x49, + 0xa5, 0x34, 0xbe, 0xce, 0x12, 0xb9, 0x7b, 0xf3, 0xbd, 0x87, 0xb9, 0x64, 0x0f, 0x64, + 0xb4, 0xca, 0x98, 0x85, 0xd3, 0xa4, 0x71, 0x41, 0x8c, 0x4c, 0xc9, 0x99, 0xaa, 0x58, + 0x27, 0xfa, 0x07, 0xb8, 0x00, 0xb0, 0x6f, 0x6f, 0x00, 0x23, 0x92, 0x53, 0xda, 0xad, + 0xdd, 0x91, 0xd2, 0xfb, 0xab, 0xd1, 0x4b, 0x57, 0xfa, 0x14, 0x82, 0x50}, + {0x4b, 0xfe, 0xd6, 0x3e, 0x15, 0x69, 0x02, 0xc2, 0xc4, 0x77, 0x1d, 0x51, 0x39, 0x67, + 0x5a, 0xa6, 0x94, 0xaf, 0x14, 0x2c, 0x46, 0x26, 0xde, 0xcb, 0x4b, 0xa7, 0xab, 0x6f, + 0xec, 0x60, 0xf9, 0x22, 0xd6, 0x03, 0xd0, 0x53, 0xbb, 0x15, 0x1a, 0x46, 0x65, 0xc9, + 0xf3, 0xbc, 0x88, 0x28, 0x10, 0xb2, 0x5a, 0x3a, 0x68, 0x6c, 0x75, 0x76, 0xc5, 0x27, + 0x47, 0xb4, 0x6c, 0xc8, 0xa4, 0x58, 0x77, 0x3a, 0x76, 0x50, 0xae, 0x93, 0xf6, 0x11, + 0x81, 0x54, 0xa6, 0x54, 0xfd, 0x1d, 0xdf, 0x21, 0xae, 0x1d, 0x65, 0x5e, 0x11, 0xf3, + 0x90, 0x8c, 0x24, 0x12, 0x94, 0xf4, 0xe7, 0x8d, 0x5f, 0xd1, 0x9f, 0x5d}, + {0x7f, 0x72, 0x63, 0x6d, 0xd3, 0x08, 0x14, 0x03, 0x33, 0xb5, 0xc7, 0xd7, 0xef, 0x9a, + 0x37, 0x6a, 0x4b, 0xe2, 0xae, 0xcc, 0xc5, 0x8f, 0xe1, 0xa9, 0xd3, 0xbe, 0x8f, 0x4f, + 0x91, 0x35, 0x2f, 0x33, 0x1e, 0x52, 0xd7, 0xee, 0x2a, 0x4d, 0x24, 0x3f, 0x15, 0x96, + 0x2e, 0x43, 0x28, 0x90, 0x3a, 0x8e, 0xd4, 0x16, 0x9c, 0x2e, 0x77, 0xba, 0x64, 0xe1, + 0xd8, 0x98, 0xeb, 0x47, 0xfa, 0x87, 0xc1, 0x3b, 0x0c, 0xc2, 0x86, 0xea, 0x15, 0x01, + 0x47, 0x6d, 0x25, 0xd1, 0x46, 0x6c, 0xcb, 0xb7, 0x8a, 0x99, 0x88, 0x01, 0x66, 0x3a, + 0xb5, 0x32, 0x78, 0xd7, 0x03, 0xba, 0x6f, 0x90, 0xce, 0x81, 0x0d, 0x45}, + {0x75, 0x52, 0x20, 0xa6, 0xa1, 0xb6, 0x7b, 0x6e, 0x83, 0x8e, 0x3c, 0x41, 0xd7, 0x21, + 0x4f, 0xaa, 0xb2, 0x5c, 0x8f, 0xe8, 0x55, 0xd1, 0x56, 0x6f, 0xe1, 0x5b, 0x34, 0xa6, + 0x4b, 0x5d, 0xe2, 0x2d, 0x3f, 0x74, 0xae, 0x1c, 0x96, 0xd8, 0x74, 0xd0, 0xed, 0x63, + 0x1c, 0xee, 0xf5, 0x18, 0x6d, 0xf8, 0x29, 0xed, 0xf4, 0xe7, 0x5b, 0xc5, 0xbd, 0x97, + 0x08, 0xb1, 0x3a, 0x66, 0x79, 0xd2, 0xba, 0x4c, 0xcd, 0x1f, 0xd7, 0xa0, 0x24, 0x90, + 0xd1, 0x80, 0xf8, 0x8a, 0x28, 0xfb, 0x0a, 0xc2, 0x25, 0xc5, 0x19, 0x64, 0x3a, 0x5f, + 0x4b, 0x97, 0xa3, 0xb1, 0x33, 0x72, 0x00, 0xe2, 0xef, 0xbc, 0x7f, 0x7d}, + {0x01, 0x28, 0x6b, 0x26, 0x6a, 0x1e, 0xef, 0xfa, 0x16, 0x9f, 0x73, 0xd5, 0xc4, 0x68, + 0x6c, 0x86, 0x2c, 0x76, 0x03, 0x1b, 0xbc, 0x2f, 0x8a, 0xf6, 0x8d, 0x5a, 0xb7, 0x87, + 0x5e, 0x43, 0x75, 0x59, 0x94, 0x90, 0xc2, 0xf3, 0xc5, 0x5d, 0x7c, 0xcd, 0xab, 0x05, + 0x91, 0x2a, 0x9a, 0xa2, 0x81, 0xc7, 0x58, 0x30, 0x1c, 0x42, 0x36, 0x1d, 0xc6, 0x80, + 0xd7, 0xd4, 0xd8, 0xdc, 0x96, 0xd1, 0x9c, 0x4f, 0x68, 0x37, 0x7b, 0x6a, 0xd8, 0x97, + 0x92, 0x19, 0x63, 0x7a, 0xd1, 0x1a, 0x24, 0x58, 0xd0, 0xd0, 0x17, 0x0c, 0x1c, 0x5c, + 0xad, 0x9c, 0x02, 0xba, 0x07, 0x03, 0x7a, 0x38, 0x84, 0xd0, 0xcd, 0x7c}, + {0x17, 0x04, 0x26, 0x6d, 0x2c, 0x42, 0xa6, 0xdc, 0xbd, 0x40, 0x82, 0x94, 0x50, 0x3d, + 0x15, 0xae, 0x77, 0xc6, 0x68, 0xfb, 0xb4, 0xc1, 0xc0, 0xa9, 0x53, 0xcf, 0xd0, 0x61, + 0xed, 0xd0, 0x8b, 0x42, 0x93, 0xcc, 0x60, 0x67, 0x18, 0x84, 0x0c, 0x9b, 0x99, 0x2a, + 0xb3, 0x1a, 0x7a, 0x00, 0xae, 0xcd, 0x18, 0xda, 0x0b, 0x62, 0x86, 0xec, 0x8d, 0xa8, + 0x44, 0xca, 0x90, 0x81, 0x84, 0xca, 0x93, 0x35, 0xa7, 0x9a, 0x84, 0x5e, 0x9a, 0x18, + 0x13, 0x92, 0xcd, 0xfa, 0xd8, 0x65, 0x35, 0xc3, 0xd8, 0xd4, 0xd1, 0xbb, 0xfd, 0x53, + 0x5b, 0x54, 0x52, 0x8c, 0xe6, 0x63, 0x2d, 0xda, 0x08, 0x83, 0x39, 0x27}, + {0x13, 0xd4, 0x5e, 0x43, 0x28, 0x8d, 0xc3, 0x42, 0xc9, 0xcc, 0x78, 0x32, 0x60, 0xf3, + 0x50, 0xbd, 0xef, 0x03, 0xda, 0x79, 0x1a, 0xab, 0x07, 0xbb, 0x55, 0x33, 0x8c, 0xbe, + 0xae, 0x97, 0x95, 0x26, 0x53, 0x24, 0x70, 0x0a, 0x4c, 0x0e, 0xa1, 0xb9, 0xde, 0x1b, + 0x7d, 0xd5, 0x66, 0x58, 0xa2, 0x0f, 0xf7, 0xda, 0x27, 0xcd, 0xb5, 0xd9, 0xb9, 0xff, + 0xfd, 0x33, 0x2c, 0x49, 0x45, 0x29, 0x2c, 0x57, 0xbe, 0x30, 0xcd, 0xd6, 0x45, 0xc7, + 0x7f, 0xc7, 0xfb, 0xae, 0xba, 0xe3, 0xd3, 0xe8, 0xdf, 0xe4, 0x0c, 0xda, 0x5d, 0xaa, + 0x30, 0x88, 0x2c, 0xa2, 0x80, 0xca, 0x5b, 0xc0, 0x98, 0x54, 0x98, 0x7f}, + {0x17, 0xe1, 0x0b, 0x9f, 0x88, 0xce, 0x49, 0x38, 0x88, 0xa2, 0x54, 0x7b, 0x1b, 0xad, + 0x05, 0x80, 0x1c, 0x92, 0xfc, 0x23, 0x9f, 0xc3, 0xa3, 0x3d, 0x04, 0xf3, 0x31, 0x0a, + 0x47, 0xec, 0xc2, 0x76, 0x63, 0x63, 0xbf, 0x0f, 0x52, 0x15, 0x56, 0xd3, 0xa6, 0xfb, + 0x4d, 0xcf, 0x45, 0x5a, 0x04, 0x08, 0xc2, 0xa0, 0x3f, 0x87, 0xbc, 0x4f, 0xc2, 0xee, + 0xe7, 0x12, 0x9b, 0xd6, 0x3c, 0x65, 0xf2, 0x30, 0x85, 0x0c, 0xc1, 0xaa, 0x38, 0xc9, + 0x08, 0x8a, 0xcb, 0x6b, 0x27, 0xdb, 0x60, 0x9b, 0x17, 0x46, 0x70, 0xac, 0x6f, 0x0e, + 0x1e, 0xc0, 0x20, 0xa9, 0xda, 0x73, 0x64, 0x59, 0xf1, 0x73, 0x12, 0x2f}, + {0x11, 0x1e, 0xe0, 0x8a, 0x7c, 0xfc, 0x39, 0x47, 0x9f, 0xab, 0x6a, 0x4a, 0x90, 0x74, + 0x52, 0xfd, 0x2e, 0x8f, 0x72, 0x87, 0x82, 0x8a, 0xd9, 0x41, 0xf2, 0x69, 0x5b, 0xd8, + 0x2a, 0x57, 0x9e, 0x5d, 0xc0, 0x0b, 0xa7, 0x55, 0xd7, 0x8b, 0x48, 0x30, 0xe7, 0x42, + 0xd4, 0xf1, 0xa4, 0xb5, 0xd6, 0x06, 0x62, 0x61, 0x59, 0xbc, 0x9e, 0xa6, 0xd1, 0xea, + 0x84, 0xf7, 0xc5, 0xed, 0x97, 0x19, 0xac, 0x38, 0x3b, 0xb1, 0x51, 0xa7, 0x17, 0xb5, + 0x66, 0x06, 0x8c, 0x85, 0x9b, 0x7e, 0x86, 0x06, 0x7d, 0x74, 0x49, 0xde, 0x4d, 0x45, + 0x11, 0xc0, 0xac, 0xac, 0x9c, 0xe6, 0xe9, 0xbf, 0x9c, 0xcd, 0xdf, 0x22}, + {0xd9, 0x0c, 0x0d, 0xc3, 0xe0, 0xd2, 0xdb, 0x8d, 0x33, 0x43, 0xbb, 0xac, 0x5f, 0x66, + 0x8e, 0xad, 0x1f, 0x96, 0x2a, 0x32, 0x8c, 0x25, 0x6b, 0x8f, 0xc7, 0xc1, 0x48, 0x54, + 0xc0, 0x16, 0x29, 0x6b, 0xa1, 0xe0, 0x3b, 0x10, 0xb4, 0x59, 0xec, 0x56, 0x69, 0xf9, + 0x59, 0xd2, 0xec, 0xba, 0xe3, 0x2e, 0x32, 0xcd, 0xf5, 0x13, 0x94, 0xb2, 0x7c, 0x79, + 0x72, 0xe4, 0xcd, 0x24, 0x78, 0x87, 0xe9, 0x0f, 0x3b, 0x91, 0xba, 0x0a, 0xd1, 0x34, + 0xdb, 0x7e, 0x0e, 0xac, 0x6d, 0x2e, 0x82, 0xcd, 0xa3, 0x4e, 0x15, 0xf8, 0x78, 0x65, + 0xff, 0x3d, 0x08, 0x66, 0x17, 0x0a, 0xf0, 0x7f, 0x30, 0x3f, 0x30, 0x4c}, + {0x85, 0x8c, 0xb2, 0x17, 0xd6, 0x3b, 0x0a, 0xd3, 0xea, 0x3b, 0x77, 0x39, 0xb7, 0x77, + 0xd3, 0xc5, 0xbf, 0x5c, 0x6a, 0x1e, 0x8c, 0xe7, 0xc6, 0xc6, 0xc4, 0xb7, 0x2a, 0x8b, + 0xf7, 0xb8, 0x61, 0x0d, 0x00, 0x45, 0xd9, 0x0d, 0x58, 0x03, 0xfc, 0x29, 0x93, 0xec, + 0xbb, 0x6f, 0xa4, 0x7a, 0xd2, 0xec, 0xf8, 0xa7, 0xe2, 0xc2, 0x5f, 0x15, 0x0a, 0x13, + 0xd5, 0xa1, 0x06, 0xb7, 0x1a, 0x15, 0x6b, 0x41, 0xb0, 0x36, 0xc1, 0xe9, 0xef, 0xd7, + 0xa8, 0x56, 0x20, 0x4b, 0xe4, 0x58, 0xcd, 0xe5, 0x07, 0xbd, 0xab, 0xe0, 0x57, 0x1b, + 0xda, 0x2f, 0xe6, 0xaf, 0xd2, 0xe8, 0x77, 0x42, 0xf7, 0x2a, 0x1a, 0x19}, + {0x31, 0x14, 0x3c, 0xc5, 0x4b, 0xf7, 0x16, 0xce, 0xde, 0xed, 0x72, 0x20, 0xce, 0x25, + 0x97, 0x2b, 0xe7, 0x3e, 0xb2, 0xb5, 0x6f, 0xc3, 0xb9, 0xb8, 0x08, 0xc9, 0x5c, 0x0b, + 0x45, 0x0e, 0x2e, 0x7e, 0xfb, 0x0e, 0x46, 0x4f, 0x43, 0x2b, 0xe6, 0x9f, 0xd6, 0x07, + 0x36, 0xa6, 0xd4, 0x03, 0xd3, 0xde, 0x24, 0xda, 0xa0, 0xb7, 0x0e, 0x21, 0x52, 0xf0, + 0x93, 0x5b, 0x54, 0x00, 0xbe, 0x7d, 0x7e, 0x23, 0x30, 0xb4, 0x01, 0x67, 0xed, 0x75, + 0x35, 0x01, 0x10, 0xfd, 0x0b, 0x9f, 0xe6, 0x94, 0x10, 0x23, 0x22, 0x7f, 0xe4, 0x83, + 0x15, 0x0f, 0x32, 0x75, 0xe3, 0x55, 0x11, 0xb1, 0x99, 0xa6, 0xaf, 0x71}, + {0x1d, 0xb6, 0x53, 0x39, 0x9b, 0x6f, 0xce, 0x65, 0xe6, 0x41, 0xa1, 0xaf, 0xea, 0x39, + 0x58, 0xc6, 0xfe, 0x59, 0xf7, 0xa9, 0xfd, 0x5f, 0x43, 0x0f, 0x8e, 0xc2, 0xb1, 0xc2, + 0xe9, 0x42, 0x11, 0x02, 0xd6, 0x50, 0x3b, 0x47, 0x1c, 0x3c, 0x42, 0xea, 0x10, 0xef, + 0x38, 0x3b, 0x1f, 0x7a, 0xe8, 0x51, 0x95, 0xbe, 0xc9, 0xb2, 0x5f, 0xbf, 0x84, 0x9b, + 0x1c, 0x9a, 0xf8, 0x78, 0xbc, 0x1f, 0x73, 0x00, 0x80, 0x18, 0xf8, 0x48, 0x18, 0xc7, + 0x30, 0xe4, 0x19, 0xc1, 0xce, 0x5e, 0x22, 0x0c, 0x96, 0xbf, 0xe3, 0x15, 0xba, 0x6b, + 0x83, 0xe0, 0xda, 0xb6, 0x08, 0x58, 0xe1, 0x47, 0x33, 0x6f, 0x4d, 0x4c}, + {0xc9, 0x1f, 0x7d, 0xc1, 0xcf, 0xec, 0xf7, 0x18, 0x14, 0x3c, 0x40, 0x51, 0xa6, 0xf5, + 0x75, 0x6c, 0xdf, 0x0c, 0xee, 0xf7, 0x2b, 0x71, 0xde, 0xdb, 0x22, 0x7a, 0xe4, 0xa7, + 0xaa, 0xdd, 0x3f, 0x19, 0x70, 0x19, 0x8f, 0x98, 0xfc, 0xdd, 0x0c, 0x2f, 0x1b, 0xf5, + 0xb9, 0xb0, 0x27, 0x62, 0x91, 0x6b, 0xbe, 0x76, 0x91, 0x77, 0xc4, 0xb6, 0xc7, 0x6e, + 0xa8, 0x9f, 0x8f, 0xa8, 0x00, 0x95, 0xbf, 0x38, 0x6f, 0x87, 0xe8, 0x37, 0x3c, 0xc9, + 0xd2, 0x1f, 0x2c, 0x46, 0xd1, 0x18, 0x5a, 0x1e, 0xf6, 0xa2, 0x76, 0x12, 0x24, 0x39, + 0x82, 0xf5, 0x80, 0x50, 0x69, 0x49, 0x0d, 0xbf, 0x9e, 0xb9, 0x6f, 0x6a}, + {0xeb, 0x55, 0x08, 0x56, 0xbb, 0xc1, 0x46, 0x6a, 0x9d, 0xf0, 0x93, 0xf8, 0x38, 0xbb, + 0x16, 0x24, 0xc1, 0xac, 0x71, 0x8f, 0x37, 0x11, 0x1d, 0xd7, 0xea, 0x96, 0x18, 0xa3, + 0x14, 0x69, 0xf7, 0x75, 0xc6, 0x23, 0xe4, 0xb6, 0xb5, 0x22, 0xb1, 0xee, 0x8e, 0xff, + 0x86, 0xf2, 0x10, 0x70, 0x9d, 0x93, 0x8c, 0x5d, 0xcf, 0x1d, 0x83, 0x2a, 0xa9, 0x90, + 0x10, 0xeb, 0xc5, 0x42, 0x9f, 0xda, 0x6f, 0x13, 0xd1, 0xbd, 0x05, 0xa3, 0xb1, 0xdf, + 0x4c, 0xf9, 0x08, 0x2c, 0xf8, 0x9f, 0x9d, 0x4b, 0x36, 0x0f, 0x8a, 0x58, 0xbb, 0xc3, + 0xa5, 0xd8, 0x87, 0x2a, 0xba, 0xdc, 0xe8, 0x0b, 0x51, 0x83, 0x21, 0x02}, + {0x14, 0x2d, 0xad, 0x5e, 0x38, 0x66, 0xf7, 0x4a, 0x30, 0x58, 0x7c, 0xca, 0x80, 0xd8, + 0x8e, 0xa0, 0x3d, 0x1e, 0x21, 0x10, 0xe6, 0xa6, 0x13, 0x0d, 0x03, 0x6c, 0x80, 0x7b, + 0xe1, 0x1c, 0x07, 0x6a, 0x7f, 0x7a, 0x30, 0x43, 0x01, 0x71, 0x5a, 0x9d, 0x5f, 0xa4, + 0x7d, 0xc4, 0x9e, 0xde, 0x63, 0xb0, 0xd3, 0x7a, 0x92, 0xbe, 0x52, 0xfe, 0xbb, 0x22, + 0x6c, 0x42, 0x40, 0xfd, 0x41, 0xc4, 0x87, 0x13, 0xf8, 0x8a, 0x97, 0x87, 0xd1, 0xc3, + 0xd3, 0xb5, 0x13, 0x44, 0x0e, 0x7f, 0x3d, 0x5a, 0x2b, 0x72, 0xa0, 0x7c, 0x47, 0xbb, + 0x48, 0x48, 0x7b, 0x0d, 0x92, 0xdc, 0x1e, 0xaf, 0x6a, 0xb2, 0x71, 0x31}, + {0xa8, 0x4c, 0x56, 0x97, 0x90, 0x31, 0x2f, 0xa9, 0x19, 0xe1, 0x75, 0x22, 0x4c, 0xb8, + 0x7b, 0xff, 0x50, 0x51, 0x87, 0xa4, 0x37, 0xfe, 0x55, 0x4f, 0x5a, 0x83, 0xf0, 0x3c, + 0x87, 0xd4, 0x1f, 0x22, 0xd1, 0x47, 0x8a, 0xb2, 0xd8, 0xb7, 0x0d, 0xa6, 0xf1, 0xa4, + 0x70, 0x17, 0xd6, 0x14, 0xbf, 0xa6, 0x58, 0xbd, 0xdd, 0x53, 0x93, 0xf8, 0xa1, 0xd4, + 0xe9, 0x43, 0x42, 0x34, 0x63, 0x4a, 0x51, 0x6c, 0x41, 0x63, 0x15, 0x3a, 0x4f, 0x20, + 0x22, 0x23, 0x2d, 0x03, 0x0a, 0xba, 0xe9, 0xe0, 0x73, 0xfb, 0x0e, 0x03, 0x0f, 0x41, + 0x4c, 0xdd, 0xe0, 0xfc, 0xaa, 0x4a, 0x92, 0xfb, 0x96, 0xa5, 0xda, 0x48}, + {0xc7, 0x9c, 0xa5, 0x5c, 0x66, 0x8e, 0xca, 0x6e, 0xa0, 0xac, 0x38, 0x2e, 0x4b, 0x25, + 0x47, 0xa8, 0xce, 0x17, 0x1e, 0xd2, 0x08, 0xc7, 0xaf, 0x31, 0xf7, 0x4a, 0xd8, 0xca, + 0xfc, 0xd6, 0x6d, 0x67, 0x93, 0x97, 0x4c, 0xc8, 0x5d, 0x1d, 0xf6, 0x14, 0x06, 0x82, + 0x41, 0xef, 0xe3, 0xf9, 0x41, 0x99, 0xac, 0x77, 0x62, 0x34, 0x8f, 0xb8, 0xf5, 0xcd, + 0xa9, 0x79, 0x8a, 0x0e, 0xfa, 0x37, 0xc8, 0x58, 0x58, 0x90, 0xfc, 0x96, 0x85, 0x68, + 0xf9, 0x0c, 0x1b, 0xa0, 0x56, 0x7b, 0xf3, 0xbb, 0xdc, 0x1d, 0x6a, 0xd6, 0x35, 0x49, + 0x7d, 0xe7, 0xc2, 0xdc, 0x0a, 0x7f, 0xa5, 0xc6, 0xf2, 0x73, 0x4f, 0x1c}, + {0xbb, 0xa0, 0x5f, 0x30, 0xbd, 0x4f, 0x7a, 0x0e, 0xad, 0x63, 0xc6, 0x54, 0xe0, 0x4c, + 0x9d, 0x82, 0x48, 0x38, 0xe3, 0x2f, 0x83, 0xc3, 0x21, 0xf4, 0x42, 0x4c, 0xf6, 0x1b, + 0x0d, 0xc8, 0x5a, 0x79, 0x84, 0x34, 0x7c, 0xfc, 0x6e, 0x70, 0x6e, 0xb3, 0x61, 0xcf, + 0xc1, 0xc3, 0xb4, 0xc9, 0xdf, 0x73, 0xe5, 0xc7, 0x1c, 0x78, 0xc9, 0x79, 0x1d, 0xeb, + 0x5c, 0x67, 0xaf, 0x7d, 0xdb, 0x9a, 0x45, 0x70, 0xb3, 0x2b, 0xb4, 0x91, 0x49, 0xdb, + 0x91, 0x1b, 0xca, 0xdc, 0x02, 0x4b, 0x23, 0x96, 0x26, 0x57, 0xdc, 0x78, 0x8c, 0x1f, + 0xe5, 0x9e, 0xdf, 0x9f, 0xd3, 0x1f, 0xe2, 0x8c, 0x84, 0x62, 0xe1, 0x5f}, + {0x1a, 0x96, 0x94, 0xe1, 0x4f, 0x21, 0x59, 0x4e, 0x4f, 0xcd, 0x71, 0x0d, 0xc7, 0x7d, + 0xbe, 0x49, 0x2d, 0xf2, 0x50, 0x3b, 0xd2, 0xcf, 0x00, 0x93, 0x32, 0x72, 0x91, 0xfc, + 0x46, 0xd4, 0x89, 0x47, 0x08, 0xb2, 0x7c, 0x5d, 0x2d, 0x85, 0x79, 0x28, 0xe7, 0xf2, + 0x7d, 0x68, 0x70, 0xdd, 0xde, 0xb8, 0x91, 0x78, 0x68, 0x21, 0xab, 0xff, 0x0b, 0xdc, + 0x35, 0xaa, 0x7d, 0x67, 0x43, 0xc0, 0x44, 0x2b, 0x8e, 0xb7, 0x4e, 0x07, 0xab, 0x87, + 0x1c, 0x1a, 0x67, 0xf4, 0xda, 0x99, 0x8e, 0xd1, 0xc6, 0xfa, 0x67, 0x90, 0x4f, 0x48, + 0xcd, 0xbb, 0xac, 0x3e, 0xe4, 0xa4, 0xb9, 0x2b, 0xef, 0x2e, 0xc5, 0x60}, + {0xf1, 0x8b, 0xfd, 0x3b, 0xbc, 0x89, 0x5d, 0x0b, 0x1a, 0x55, 0xf3, 0xc9, 0x37, 0x92, + 0x6b, 0xb0, 0xf5, 0x28, 0x30, 0xd5, 0xb0, 0x16, 0x4c, 0x0e, 0xab, 0xca, 0xcf, 0x2c, + 0x31, 0x9c, 0xbc, 0x10, 0x11, 0x6d, 0xae, 0x7c, 0xc2, 0xc5, 0x2b, 0x70, 0xab, 0x8c, + 0xa4, 0x54, 0x9b, 0x69, 0xc7, 0x44, 0xb2, 0x2e, 0x49, 0xba, 0x56, 0x40, 0xbc, 0xef, + 0x6d, 0x67, 0xb6, 0xd9, 0x48, 0x72, 0xd7, 0x70, 0x5b, 0xa0, 0xc2, 0x3e, 0x4b, 0xe8, + 0x8a, 0xaa, 0xe0, 0x81, 0x17, 0xed, 0xf4, 0x9e, 0x69, 0x98, 0xd1, 0x85, 0x8e, 0x70, + 0xe4, 0x13, 0x45, 0x79, 0x13, 0xf4, 0x76, 0xa9, 0xd3, 0x5b, 0x75, 0x63}, + {0x53, 0x08, 0xd1, 0x2a, 0x3e, 0xa0, 0x5f, 0xb5, 0x69, 0x35, 0xe6, 0x9e, 0x90, 0x75, + 0x6f, 0x35, 0x90, 0xb8, 0x69, 0xbe, 0xfd, 0xf1, 0xf9, 0x9f, 0x84, 0x6f, 0xc1, 0x8b, + 0xc4, 0xc1, 0x8c, 0x0d, 0xb7, 0xac, 0xf1, 0x97, 0x18, 0x10, 0xc7, 0x3d, 0xd8, 0xbb, + 0x65, 0xc1, 0x5e, 0x7d, 0xda, 0x5d, 0x0f, 0x02, 0xa1, 0x0f, 0x9c, 0x5b, 0x8e, 0x50, + 0x56, 0x2a, 0xc5, 0x37, 0x17, 0x75, 0x63, 0x27, 0xa9, 0x19, 0xb4, 0x6e, 0xd3, 0x02, + 0x94, 0x02, 0xa5, 0x60, 0xb4, 0x77, 0x7e, 0x4e, 0xb4, 0xf0, 0x56, 0x49, 0x3c, 0xd4, + 0x30, 0x62, 0xa8, 0xcf, 0xe7, 0x66, 0xd1, 0x7a, 0x8a, 0xdd, 0xc2, 0x70}, + {0x0e, 0xec, 0x6f, 0x9f, 0x50, 0x94, 0x61, 0x65, 0x8d, 0x51, 0xc6, 0x46, 0xa9, 0x7e, + 0x2e, 0xee, 0x5c, 0x9b, 0xe0, 0x67, 0xf3, 0xc1, 0x33, 0x97, 0x95, 0x84, 0x94, 0x63, + 0x63, 0xac, 0x0f, 0x2e, 0x13, 0x7e, 0xed, 0xb8, 0x7d, 0x96, 0xd4, 0x91, 0x7a, 0x81, + 0x76, 0xd7, 0x0a, 0x2f, 0x25, 0x74, 0x64, 0x25, 0x85, 0x0d, 0xe0, 0x82, 0x09, 0xe4, + 0xe5, 0x3c, 0xa5, 0x16, 0x38, 0x61, 0xb8, 0x32, 0x64, 0xcd, 0x48, 0xe4, 0xbe, 0xf7, + 0xe7, 0x79, 0xd0, 0x86, 0x78, 0x08, 0x67, 0x3a, 0xc8, 0x6a, 0x2e, 0xdb, 0xe4, 0xa0, + 0xd9, 0xd4, 0x9f, 0xf8, 0x41, 0x4f, 0x5a, 0x73, 0x5c, 0x21, 0x79, 0x41}, + {0x2a, 0xed, 0xdc, 0xd7, 0xe7, 0x94, 0x70, 0x8c, 0x70, 0x9c, 0xd3, 0x47, 0xc3, 0x8a, + 0xfb, 0x97, 0x02, 0xd9, 0x06, 0xa9, 0x33, 0xe0, 0x3b, 0xe1, 0x76, 0x9d, 0xd9, 0x0c, + 0xa3, 0x44, 0x03, 0x70, 0x34, 0xcd, 0x6b, 0x28, 0xb9, 0x33, 0xae, 0xe4, 0xdc, 0xd6, + 0x9d, 0x55, 0xb6, 0x7e, 0xef, 0xb7, 0x1f, 0x8e, 0xd3, 0xb3, 0x1f, 0x14, 0x8b, 0x27, + 0x86, 0xc2, 0x41, 0x22, 0x66, 0x85, 0xfa, 0x31, 0xf4, 0x22, 0x36, 0x2e, 0x42, 0x6c, + 0x82, 0xaf, 0x2d, 0x50, 0x33, 0x98, 0x87, 0x29, 0x20, 0xc1, 0x23, 0x91, 0x38, 0x2b, + 0xe1, 0xb7, 0xc1, 0x9b, 0x89, 0x24, 0x95, 0xa9, 0x12, 0x23, 0xbb, 0x24}, + {0xc3, 0x67, 0xde, 0x32, 0x17, 0xed, 0xa8, 0xb1, 0x48, 0x49, 0x1b, 0x46, 0x18, 0x94, + 0xb4, 0x3c, 0xd2, 0xbc, 0xcf, 0x76, 0x43, 0x43, 0xbd, 0x8e, 0x08, 0x80, 0x18, 0x1e, + 0x87, 0x3e, 0xee, 0x0f, 0x6b, 0x5c, 0xf8, 0xf5, 0x2a, 0x0c, 0xf8, 0x41, 0x94, 0x67, + 0xfa, 0x04, 0xc3, 0x84, 0x72, 0x68, 0xad, 0x1b, 0xba, 0xa3, 0x99, 0xdf, 0x45, 0x89, + 0x16, 0x5d, 0xeb, 0xff, 0xf9, 0x2a, 0x1d, 0x0d, 0xdf, 0x1e, 0x62, 0x32, 0xa1, 0x8a, + 0xda, 0xa9, 0x79, 0x65, 0x22, 0x59, 0xa1, 0x22, 0xb8, 0x30, 0x93, 0xc1, 0x9a, 0xa7, + 0x7b, 0x19, 0x04, 0x40, 0x76, 0x1d, 0x53, 0x18, 0x97, 0xd7, 0xac, 0x16}, + {0x3d, 0x1d, 0x9b, 0x2d, 0xaf, 0x72, 0xdf, 0x72, 0x5a, 0x24, 0x32, 0xa4, 0x36, 0x2a, + 0x46, 0x63, 0x37, 0x96, 0xb3, 0x16, 0x79, 0xa0, 0xce, 0x3e, 0x09, 0x23, 0x30, 0xb9, + 0xf6, 0x0e, 0x3e, 0x12, 0xad, 0xb6, 0x87, 0x78, 0xc5, 0xc6, 0x59, 0xc9, 0xba, 0xfe, + 0x90, 0x5f, 0xad, 0x9e, 0xe1, 0x94, 0x04, 0xf5, 0x42, 0xa3, 0x62, 0x4e, 0xe2, 0x16, + 0x00, 0x17, 0x16, 0x18, 0x4b, 0xd3, 0x4e, 0x16, 0x9a, 0xe6, 0x2f, 0x19, 0x4c, 0xd9, + 0x7e, 0x48, 0x13, 0x15, 0x91, 0x3a, 0xea, 0x2c, 0xae, 0x61, 0x27, 0xde, 0xa4, 0xb9, + 0xd3, 0xf6, 0x7b, 0x87, 0xeb, 0xf3, 0x73, 0x10, 0xc6, 0x0f, 0xda, 0x78}, + {0x6a, 0xc6, 0x2b, 0xe5, 0x28, 0x5d, 0xf1, 0x5b, 0x8e, 0x1a, 0xf0, 0x70, 0x18, 0xe3, + 0x47, 0x2c, 0xdd, 0x8b, 0xc2, 0x06, 0xbc, 0xaf, 0x19, 0x24, 0x3a, 0x17, 0x6b, 0x25, + 0xeb, 0xde, 0x25, 0x2d, 0x94, 0x3a, 0x0c, 0x68, 0xf1, 0x80, 0x9f, 0xa2, 0xe6, 0xe7, + 0xe9, 0x1a, 0x15, 0x7e, 0xf7, 0x71, 0x73, 0x79, 0x01, 0x48, 0x58, 0xf1, 0x00, 0x11, + 0xdd, 0x8d, 0xb3, 0x16, 0xb3, 0xa4, 0x4a, 0x05, 0xb8, 0x7c, 0x26, 0x19, 0x8d, 0x46, + 0xc8, 0xdf, 0xaf, 0x4d, 0xe5, 0x66, 0x9c, 0x78, 0x28, 0x0b, 0x17, 0xec, 0x6e, 0x66, + 0x2a, 0x1d, 0xeb, 0x2a, 0x60, 0xa7, 0x7d, 0xab, 0xa6, 0x10, 0x46, 0x13}, + {0xfe, 0xb0, 0xf6, 0x8d, 0xc7, 0x8e, 0x13, 0x51, 0x1b, 0xf5, 0x75, 0xe5, 0x89, 0xda, + 0x97, 0x53, 0xb9, 0xf1, 0x7a, 0x71, 0x1d, 0x7a, 0x20, 0x09, 0x50, 0xd6, 0x20, 0x2b, + 0xba, 0xfd, 0x02, 0x21, 0x15, 0xf5, 0xd1, 0x77, 0xe7, 0x65, 0x2a, 0xcd, 0xf1, 0x60, + 0xaa, 0x8f, 0x87, 0x91, 0x89, 0x54, 0xe5, 0x06, 0xbc, 0xda, 0xbc, 0x3b, 0xb7, 0xb1, + 0xfb, 0xc9, 0x7c, 0xa9, 0xcb, 0x78, 0x48, 0x65, 0xa1, 0xe6, 0x5c, 0x05, 0x05, 0xe4, + 0x9e, 0x96, 0x29, 0xad, 0x51, 0x12, 0x68, 0xa7, 0xbc, 0x36, 0x15, 0xa4, 0x7d, 0xaa, + 0x17, 0xf5, 0x1a, 0x3a, 0xba, 0xb2, 0xec, 0x29, 0xdb, 0x25, 0xd7, 0x0a}, + {0x57, 0x24, 0x4e, 0x83, 0xb1, 0x67, 0x42, 0xdc, 0xc5, 0x1b, 0xce, 0x70, 0xb5, 0x44, + 0x75, 0xb6, 0xd7, 0x5e, 0xd1, 0xf7, 0x0b, 0x7a, 0xf0, 0x1a, 0x50, 0x36, 0xa0, 0x71, + 0xfb, 0xcf, 0xef, 0x4a, 0x85, 0x6f, 0x05, 0x9b, 0x0c, 0xbc, 0xc7, 0xfe, 0xd7, 0xff, + 0xf5, 0xe7, 0x68, 0x52, 0x7d, 0x53, 0xfa, 0xae, 0x12, 0x43, 0x62, 0xc6, 0xaf, 0x77, + 0xd9, 0x9f, 0x39, 0x02, 0x53, 0x5f, 0x67, 0x4f, 0x1e, 0x17, 0x15, 0x04, 0x36, 0x36, + 0x2d, 0xc3, 0x3b, 0x48, 0x98, 0x89, 0x11, 0xef, 0x2b, 0xcd, 0x10, 0x51, 0x94, 0xd0, + 0xad, 0x6e, 0x0a, 0x87, 0x61, 0x65, 0xa8, 0xa2, 0x72, 0xbb, 0xcc, 0x0b}, + {0xc8, 0xa9, 0xb1, 0xea, 0x2f, 0x96, 0x5e, 0x18, 0xcd, 0x7d, 0x14, 0x65, 0x35, 0xe6, + 0xe7, 0x86, 0xf2, 0x6d, 0x5b, 0xbb, 0x31, 0xe0, 0x92, 0xb0, 0x3e, 0xb7, 0xd6, 0x59, + 0xab, 0xf0, 0x24, 0x40, 0x96, 0x12, 0xfe, 0x50, 0x4c, 0x5e, 0x6d, 0x18, 0x7e, 0x9f, + 0xe8, 0xfe, 0x82, 0x7b, 0x39, 0xe0, 0xb0, 0x31, 0x70, 0x50, 0xc5, 0xf6, 0xc7, 0x3b, + 0xc2, 0x37, 0x8f, 0x10, 0x69, 0xfd, 0x78, 0x66, 0xc2, 0x63, 0x68, 0x63, 0x31, 0xfa, + 0x86, 0x15, 0xf2, 0x33, 0x2d, 0x57, 0x48, 0x8c, 0xf6, 0x07, 0xfc, 0xae, 0x9e, 0x78, + 0x9f, 0xcc, 0x73, 0x4f, 0x01, 0x47, 0xad, 0x8e, 0x10, 0xe2, 0x42, 0x2d}, + {0x9b, 0xd2, 0xdf, 0x94, 0x15, 0x13, 0xf5, 0x97, 0x6a, 0x4c, 0x3f, 0x31, 0x5d, 0x98, + 0x55, 0x61, 0x10, 0x50, 0x45, 0x08, 0x07, 0x3f, 0xa1, 0xeb, 0x22, 0xd3, 0xd2, 0xb8, + 0x08, 0x26, 0x6b, 0x67, 0x93, 0x75, 0x53, 0x0f, 0x0d, 0x7b, 0x71, 0x21, 0x4c, 0x06, + 0x1e, 0x13, 0x0b, 0x69, 0x4e, 0x91, 0x9f, 0xe0, 0x2a, 0x75, 0xae, 0x87, 0xb6, 0x1b, + 0x6e, 0x3c, 0x42, 0x9b, 0xa7, 0xf3, 0x0b, 0x42, 0x47, 0x2b, 0x5b, 0x1c, 0x65, 0xba, + 0x38, 0x81, 0x80, 0x1b, 0x1b, 0x31, 0xec, 0xb6, 0x71, 0x86, 0xb0, 0x35, 0x31, 0xbc, + 0xb1, 0x0c, 0xff, 0x7b, 0xe0, 0xf1, 0x0c, 0x9c, 0xfa, 0x2f, 0x5d, 0x74}, + {0xbd, 0xc8, 0xc9, 0x2b, 0x1e, 0x5a, 0x52, 0xbf, 0x81, 0x9d, 0x47, 0x26, 0x08, 0x26, + 0x5b, 0xea, 0xdb, 0x55, 0x01, 0xdf, 0x0e, 0xc7, 0x11, 0xd5, 0xd0, 0xf5, 0x0c, 0x96, + 0xeb, 0x3c, 0xe2, 0x1a, 0x6a, 0x4e, 0xd3, 0x21, 0x57, 0xdf, 0x36, 0x60, 0xd0, 0xb3, + 0x7b, 0x99, 0x27, 0x88, 0xdb, 0xb1, 0xfa, 0x6a, 0x75, 0xc8, 0xc3, 0x09, 0xc2, 0xd3, + 0x39, 0xc8, 0x1d, 0x4c, 0xe5, 0x5b, 0xe1, 0x06, 0x4a, 0x99, 0x32, 0x19, 0x87, 0x5d, + 0x72, 0x5b, 0xb0, 0xda, 0xb1, 0xce, 0xb5, 0x1c, 0x35, 0x32, 0x05, 0xca, 0xb7, 0xda, + 0x49, 0x15, 0xc4, 0x7d, 0xf7, 0xc1, 0x8e, 0x27, 0x61, 0xd8, 0xde, 0x58}, + {0x5c, 0xc5, 0x66, 0xf2, 0x93, 0x37, 0x17, 0xd8, 0x49, 0x4e, 0x45, 0xcc, 0xc5, 0x76, + 0xc9, 0xc8, 0xa8, 0xc3, 0x26, 0xbc, 0xf8, 0x82, 0xe3, 0x5c, 0xf9, 0xf6, 0x85, 0x54, + 0xe8, 0x9d, 0xf3, 0x2f, 0xa8, 0xc9, 0xc2, 0xb6, 0xa8, 0x5b, 0xfb, 0x2d, 0x8c, 0x59, + 0x2c, 0xf5, 0x8e, 0xef, 0xee, 0x48, 0x73, 0x15, 0x2d, 0xf1, 0x07, 0x91, 0x80, 0x33, + 0xd8, 0x5b, 0x1d, 0x53, 0x6b, 0x69, 0xba, 0x08, 0x7a, 0xc5, 0xef, 0xc3, 0xee, 0x3e, + 0xed, 0x77, 0x11, 0x48, 0xff, 0xd4, 0x17, 0x55, 0xe0, 0x04, 0xcb, 0x71, 0xa6, 0xf1, + 0x3f, 0x7a, 0x3d, 0xea, 0x54, 0xfe, 0x7c, 0x94, 0xb4, 0x33, 0x06, 0x12}, + {0x42, 0x00, 0x61, 0x91, 0x78, 0x98, 0x94, 0x0b, 0xe8, 0xfa, 0xeb, 0xec, 0x3c, 0xb1, + 0xe7, 0x4e, 0xc0, 0xa4, 0xf0, 0x94, 0x95, 0x73, 0xbe, 0x70, 0x85, 0x91, 0xd5, 0xb4, + 0x99, 0x0a, 0xd3, 0x35, 0x0a, 0x10, 0x12, 0x49, 0x47, 0x31, 0xbd, 0x82, 0x06, 0xbe, + 0x6f, 0x7e, 0x6d, 0x7b, 0x23, 0xde, 0xc6, 0x79, 0xea, 0x11, 0x19, 0x76, 0x1e, 0xe1, + 0xde, 0x3b, 0x39, 0xcb, 0xe3, 0x3b, 0x43, 0x07, 0xf4, 0x97, 0xe9, 0x5c, 0xc0, 0x44, + 0x79, 0xff, 0xa3, 0x51, 0x5c, 0xb0, 0xe4, 0x3d, 0x5d, 0x57, 0x7c, 0x84, 0x76, 0x5a, + 0xfd, 0x81, 0x33, 0x58, 0x9f, 0xda, 0xf6, 0x7a, 0xde, 0x3e, 0x87, 0x2d}, + {0x09, 0x34, 0x37, 0x43, 0x64, 0x31, 0x7a, 0x15, 0xd9, 0x81, 0xaa, 0xf4, 0xee, 0xb7, + 0xb8, 0xfa, 0x06, 0x48, 0xa6, 0xf5, 0xe6, 0xfe, 0x93, 0xb0, 0xb6, 0xa7, 0x7f, 0x70, + 0x54, 0x36, 0x77, 0x2e, 0x81, 0xf9, 0x5d, 0x4e, 0xe1, 0x02, 0x62, 0xaa, 0xf5, 0xe1, + 0x15, 0x50, 0x17, 0x59, 0x0d, 0xa2, 0x6c, 0x1d, 0xe2, 0xba, 0xd3, 0x75, 0xa2, 0x18, + 0x53, 0x02, 0x60, 0x01, 0x8a, 0x61, 0x43, 0x05, 0xc1, 0x23, 0x4c, 0x97, 0xf4, 0xbd, + 0xea, 0x0d, 0x93, 0x46, 0xce, 0x9d, 0x25, 0x0a, 0x6f, 0xaa, 0x2c, 0xba, 0x9a, 0xa2, + 0xb8, 0x2c, 0x20, 0x04, 0x0d, 0x96, 0x07, 0x2d, 0x36, 0x43, 0x14, 0x4b}, + {0x7a, 0x1f, 0x6e, 0xb6, 0xc7, 0xb7, 0xc4, 0xcc, 0x7e, 0x2f, 0x0c, 0xf5, 0x25, 0x7e, + 0x15, 0x44, 0x1c, 0xaf, 0x3e, 0x71, 0xfc, 0x6d, 0xf0, 0x3e, 0xf7, 0x63, 0xda, 0x52, + 0x67, 0x44, 0x2f, 0x58, 0xcb, 0x9c, 0x52, 0x1c, 0xe9, 0x54, 0x7c, 0x96, 0xfb, 0x35, + 0xc6, 0x64, 0x92, 0x26, 0xf6, 0x30, 0x65, 0x19, 0x12, 0x78, 0xf4, 0xaf, 0x47, 0x27, + 0x5c, 0x6f, 0xf6, 0xea, 0x18, 0x84, 0x03, 0x17, 0xe4, 0x4c, 0x32, 0x20, 0xd3, 0x7b, + 0x31, 0xc6, 0xc4, 0x8b, 0x48, 0xa4, 0xe8, 0x42, 0x10, 0xa8, 0x64, 0x13, 0x5a, 0x4e, + 0x8b, 0xf1, 0x1e, 0xb2, 0xc9, 0x8d, 0xa2, 0xcd, 0x4b, 0x1c, 0x2a, 0x0c}, + {0x47, 0x04, 0x1f, 0x6f, 0xd0, 0xc7, 0x4d, 0xd2, 0x59, 0xc0, 0x87, 0xdb, 0x3e, 0x9e, + 0x26, 0xb2, 0x8f, 0xd2, 0xb2, 0xfb, 0x72, 0x02, 0x5b, 0xd1, 0x77, 0x48, 0xf6, 0xc6, + 0xd1, 0x8b, 0x55, 0x7c, 0x45, 0x69, 0xbd, 0x69, 0x48, 0x81, 0xc4, 0xed, 0x22, 0x8d, + 0x1c, 0xbe, 0x7d, 0x90, 0x6d, 0x0d, 0xab, 0xc5, 0x5c, 0xd5, 0x12, 0xd2, 0x3b, 0xc6, + 0x83, 0xdc, 0x14, 0xa3, 0x30, 0x9b, 0x6a, 0x5a, 0x3d, 0x46, 0x96, 0xd3, 0x24, 0x15, + 0xec, 0xd0, 0xf0, 0x24, 0x5a, 0xc3, 0x8a, 0x62, 0xbb, 0x12, 0xa4, 0x5f, 0xbc, 0x1c, + 0x79, 0x3a, 0x0c, 0xa5, 0xc3, 0xaf, 0xfb, 0x0a, 0xca, 0xa5, 0x04, 0x04}, + {0xd6, 0x43, 0xa7, 0x0a, 0x07, 0x40, 0x1f, 0x8c, 0xe8, 0x5e, 0x26, 0x5b, 0xcb, 0xd0, + 0xba, 0xcc, 0xde, 0xd2, 0x8f, 0x66, 0x6b, 0x04, 0x4b, 0x57, 0x33, 0x96, 0xdd, 0xca, + 0xfd, 0x5b, 0x39, 0x46, 0xd1, 0x6f, 0x41, 0x2a, 0x1b, 0x9e, 0xbc, 0x62, 0x8b, 0x59, + 0x50, 0xe3, 0x28, 0xf7, 0xc6, 0xb5, 0x67, 0x69, 0x5d, 0x3d, 0xd8, 0x3f, 0x34, 0x04, + 0x98, 0xee, 0xf8, 0xe7, 0x16, 0x75, 0x52, 0x39, 0x9c, 0x9a, 0x5d, 0x1a, 0x2d, 0xdb, + 0x7f, 0x11, 0x2a, 0x5c, 0x00, 0xd1, 0xbc, 0x45, 0x77, 0x9c, 0xea, 0x6f, 0xd5, 0x54, + 0xf1, 0xbe, 0xd4, 0xef, 0x16, 0xd0, 0x22, 0xe8, 0x29, 0x9a, 0x57, 0x76}, + {0x17, 0x2a, 0xc0, 0x49, 0x7e, 0x8e, 0xb6, 0x45, 0x7f, 0xa3, 0xa9, 0xbc, 0xa2, 0x51, + 0xcd, 0x23, 0x1b, 0x4c, 0x22, 0xec, 0x11, 0x5f, 0xd6, 0x3e, 0xb1, 0xbd, 0x05, 0x9e, + 0xdc, 0x84, 0xa3, 0x43, 0xf2, 0x34, 0xb4, 0x52, 0x13, 0xb5, 0x3c, 0x33, 0xe1, 0x80, + 0xde, 0x93, 0x49, 0x28, 0x32, 0xd8, 0xce, 0x35, 0x0d, 0x75, 0x87, 0x28, 0x51, 0xb5, + 0xc1, 0x77, 0x27, 0x2a, 0xbb, 0x14, 0xc5, 0x02, 0x45, 0xb6, 0xf1, 0x8b, 0xda, 0xd5, + 0x4b, 0x68, 0x53, 0x4b, 0xb5, 0xf6, 0x7e, 0xd3, 0x8b, 0xfb, 0x53, 0xd2, 0xb0, 0xa9, + 0xd7, 0x16, 0x39, 0x31, 0x59, 0x80, 0x54, 0x61, 0x09, 0x92, 0x60, 0x11}, + {0xaa, 0xcf, 0xda, 0x29, 0x69, 0x16, 0x4d, 0xb4, 0x8f, 0x59, 0x13, 0x84, 0x4c, 0x9f, + 0x52, 0xda, 0x59, 0x55, 0x3d, 0x45, 0xca, 0x63, 0xef, 0xe9, 0x0b, 0x8e, 0x69, 0xc5, + 0x5b, 0x12, 0x1e, 0x35, 0xcd, 0x4d, 0x9b, 0x36, 0x16, 0x56, 0x38, 0x7a, 0x63, 0x35, + 0x5c, 0x65, 0xa7, 0x2c, 0xc0, 0x75, 0x21, 0x80, 0xf1, 0xd4, 0xf9, 0x1b, 0xc2, 0x7d, + 0x42, 0xe0, 0xe6, 0x91, 0x74, 0x7d, 0x63, 0x2f, 0xbe, 0x7b, 0xf6, 0x1a, 0x46, 0x9b, + 0xb4, 0xd4, 0x61, 0x89, 0xab, 0xc8, 0x7a, 0x03, 0x03, 0xd6, 0xfb, 0x99, 0xa6, 0xf9, + 0x9f, 0xe1, 0xde, 0x71, 0x9a, 0x2a, 0xce, 0xe7, 0x06, 0x2d, 0x18, 0x7f}, + {0xec, 0x68, 0x01, 0xab, 0x64, 0x8e, 0x7c, 0x7a, 0x43, 0xc5, 0xed, 0x15, 0x55, 0x4a, + 0x5a, 0xcb, 0xda, 0x0e, 0xcd, 0x47, 0xd3, 0x19, 0x55, 0x09, 0xb0, 0x93, 0x3e, 0x34, + 0x8c, 0xac, 0xd4, 0x67, 0x22, 0x75, 0x21, 0x8e, 0x72, 0x4b, 0x45, 0x09, 0xd8, 0xb8, + 0x84, 0xd4, 0xf4, 0xe8, 0x58, 0xaa, 0x3c, 0x90, 0x46, 0x7f, 0x4d, 0x25, 0x58, 0xd3, + 0x17, 0x52, 0x1c, 0x24, 0x43, 0xc0, 0xac, 0x44, 0x77, 0x57, 0x7a, 0x4f, 0xbb, 0x6b, + 0x7d, 0x1c, 0xe1, 0x13, 0x83, 0x91, 0xd4, 0xfe, 0x35, 0x8b, 0x84, 0x46, 0x6b, 0xc9, + 0xc6, 0xa1, 0xdc, 0x4a, 0xbd, 0x71, 0xad, 0x12, 0x83, 0x1c, 0x6d, 0x55}, + {0x82, 0x39, 0x8d, 0x0c, 0xe3, 0x40, 0xef, 0x17, 0x34, 0xfa, 0xa3, 0x15, 0x3e, 0x07, + 0xf7, 0x31, 0x6e, 0x64, 0x73, 0x07, 0xcb, 0xf3, 0x21, 0x4f, 0xff, 0x4e, 0x82, 0x1d, + 0x6d, 0x6c, 0x6c, 0x74, 0x21, 0xe8, 0x1b, 0xb1, 0x56, 0x67, 0xf0, 0x81, 0xdd, 0xf3, + 0xa3, 0x10, 0x23, 0xf8, 0xaf, 0x0f, 0x5d, 0x46, 0x99, 0x6a, 0x55, 0xd0, 0xb2, 0xf8, + 0x05, 0x7f, 0x8c, 0xcc, 0x38, 0xbe, 0x7a, 0x09, 0xa4, 0x2d, 0xa5, 0x7e, 0x87, 0xc9, + 0x49, 0x0c, 0x43, 0x1d, 0xdc, 0x9b, 0x55, 0x69, 0x43, 0x4c, 0xd2, 0xeb, 0xcc, 0xf7, + 0x09, 0x38, 0x2c, 0x02, 0xbd, 0x84, 0xee, 0x4b, 0xa3, 0x14, 0x7e, 0x57}, + {0x0a, 0x3b, 0xa7, 0x61, 0xac, 0x68, 0xe2, 0xf0, 0xf5, 0xa5, 0x91, 0x37, 0x10, 0xfa, + 0xfa, 0xf2, 0xe9, 0x00, 0x6d, 0x6b, 0x82, 0x3e, 0xe1, 0xc1, 0x42, 0x8f, 0xd7, 0x6f, + 0xe9, 0x7e, 0xfa, 0x60, 0x2b, 0xd7, 0x4d, 0xbd, 0xbe, 0xce, 0xfe, 0x94, 0x11, 0x22, + 0x0f, 0x06, 0xda, 0x4f, 0x6a, 0xf4, 0xff, 0xd1, 0xc8, 0xc0, 0x77, 0x59, 0x4a, 0x12, + 0x95, 0x92, 0x00, 0xfb, 0xb8, 0x04, 0x53, 0x70, 0xc6, 0x6e, 0x29, 0x4d, 0x35, 0x1d, + 0x3d, 0xb6, 0xd8, 0x31, 0xad, 0x5f, 0x3e, 0x05, 0xc3, 0xf3, 0xec, 0x42, 0xbd, 0xb4, + 0x8c, 0x95, 0x0b, 0x67, 0xfd, 0x53, 0x63, 0xa1, 0x0c, 0x8e, 0x39, 0x21}, + {0xf3, 0x33, 0x2b, 0x38, 0x8a, 0x05, 0xf5, 0x89, 0xb4, 0xc0, 0x48, 0xad, 0x0b, 0xba, + 0xe2, 0x5a, 0x6e, 0xb3, 0x3d, 0xa5, 0x03, 0xb5, 0x93, 0x8f, 0xe6, 0x32, 0xa2, 0x95, + 0x9d, 0xed, 0xa3, 0x5a, 0x01, 0x56, 0xb7, 0xb4, 0xf9, 0xaa, 0x98, 0x27, 0x72, 0xad, + 0x8d, 0x5c, 0x13, 0x72, 0xac, 0x5e, 0x23, 0xa0, 0xb7, 0x61, 0x61, 0xaa, 0xce, 0xd2, + 0x4e, 0x7d, 0x8f, 0xe9, 0x84, 0xb2, 0xbf, 0x1b, 0x61, 0x65, 0xd9, 0xc7, 0xe9, 0x77, + 0x67, 0x65, 0x36, 0x80, 0xc7, 0x72, 0x54, 0x12, 0x2b, 0xcb, 0xee, 0x6e, 0x50, 0xd9, + 0x99, 0x32, 0x05, 0x65, 0xcc, 0x57, 0x89, 0x5e, 0x4e, 0xe1, 0x07, 0x4a}, + {0x99, 0xf9, 0x0d, 0x98, 0xcb, 0x12, 0xe4, 0x4e, 0x71, 0xc7, 0x6e, 0x3c, 0x6f, 0xd7, + 0x15, 0xa3, 0xfd, 0x77, 0x5c, 0x92, 0xde, 0xed, 0xa5, 0xbb, 0x02, 0x34, 0x31, 0x1d, + 0x39, 0xac, 0x0b, 0x3f, 0x9b, 0xa4, 0x77, 0xc4, 0xcd, 0x58, 0x0b, 0x24, 0x17, 0xf0, + 0x47, 0x64, 0xde, 0xda, 0x38, 0xfd, 0xad, 0x6a, 0xc8, 0xa7, 0x32, 0x8d, 0x92, 0x19, + 0x81, 0xa0, 0xaf, 0x84, 0xed, 0x7a, 0xaf, 0x50, 0xe5, 0x5b, 0xf6, 0x15, 0x01, 0xde, + 0x4f, 0x6e, 0xb2, 0x09, 0x61, 0x21, 0x21, 0x26, 0x98, 0x29, 0xd9, 0xd6, 0xad, 0x0b, + 0x81, 0x05, 0x02, 0x78, 0x06, 0xd0, 0xeb, 0xba, 0x16, 0xa3, 0x21, 0x19}, + {0xfc, 0x70, 0xb8, 0xdf, 0x7e, 0x2f, 0x42, 0x89, 0xbd, 0xb3, 0x76, 0x4f, 0xeb, 0x6b, + 0x29, 0x2c, 0xf7, 0x4d, 0xc2, 0x36, 0xd4, 0xf1, 0x38, 0x07, 0xb0, 0xae, 0x73, 0xe2, + 0x41, 0xdf, 0x58, 0x64, 0x8b, 0xc1, 0xf3, 0xd9, 0x9a, 0xad, 0x5a, 0xd7, 0x9c, 0xc1, + 0xb1, 0x60, 0xef, 0x0e, 0x6a, 0x56, 0xd9, 0x0e, 0x5c, 0x25, 0xac, 0x0b, 0x9a, 0x3e, + 0xf5, 0xc7, 0x62, 0xa0, 0xec, 0x9d, 0x04, 0x7b, 0x83, 0x44, 0x44, 0x35, 0x7a, 0xe3, + 0xcb, 0xdc, 0x93, 0xbe, 0xed, 0x0f, 0x33, 0x79, 0x88, 0x75, 0x87, 0xdd, 0xc5, 0x12, + 0xc3, 0x04, 0x60, 0x78, 0x64, 0x0e, 0x95, 0xc2, 0xcb, 0xdc, 0x93, 0x60}, + {0x6d, 0x70, 0xe0, 0x85, 0x85, 0x9a, 0xf3, 0x1f, 0x33, 0x39, 0xe7, 0xb3, 0xd8, 0xa5, + 0xd0, 0x36, 0x3b, 0x45, 0x8f, 0x71, 0xe1, 0xf2, 0xb9, 0x43, 0x7c, 0xa9, 0x27, 0x48, + 0x08, 0xea, 0xd1, 0x57, 0x4b, 0x03, 0x84, 0x60, 0xbe, 0xee, 0xde, 0x6b, 0x54, 0xb8, + 0x0f, 0x78, 0xb6, 0xc2, 0x99, 0x31, 0x95, 0x06, 0x2d, 0xb6, 0xab, 0x76, 0x33, 0x97, + 0x90, 0x7d, 0x64, 0x8b, 0xc9, 0x80, 0x31, 0x6e, 0x71, 0xb0, 0x28, 0xa1, 0xe7, 0xb6, + 0x7a, 0xee, 0xaa, 0x8b, 0xa8, 0x93, 0x6d, 0x59, 0xc1, 0xa4, 0x30, 0x61, 0x21, 0xb2, + 0x82, 0xde, 0xb4, 0xf7, 0x18, 0xbd, 0x97, 0xdd, 0x9d, 0x99, 0x3e, 0x36}, + {0xc4, 0x1f, 0xee, 0x35, 0xc1, 0x43, 0xa8, 0x96, 0xcf, 0xc8, 0xe4, 0x08, 0x55, 0xb3, + 0x6e, 0x97, 0x30, 0xd3, 0x8c, 0xb5, 0x01, 0x68, 0x2f, 0xb4, 0x2b, 0x05, 0x3a, 0x69, + 0x78, 0x9b, 0xee, 0x48, 0xc6, 0xae, 0x4b, 0xe2, 0xdc, 0x48, 0x18, 0x2f, 0x60, 0xaf, + 0xbc, 0xba, 0x55, 0x72, 0x9b, 0x76, 0x31, 0xe9, 0xef, 0x3c, 0x6e, 0x3c, 0xcb, 0x90, + 0x55, 0xb3, 0xf9, 0xc6, 0x9b, 0x97, 0x1f, 0x23, 0xc6, 0xf3, 0x2a, 0xcc, 0x4b, 0xde, + 0x31, 0x5c, 0x1f, 0x8d, 0x20, 0xfe, 0x30, 0xb0, 0x4b, 0xb0, 0x66, 0xb4, 0x4f, 0xc1, + 0x09, 0x70, 0x8d, 0xb7, 0x13, 0x24, 0x79, 0x08, 0x9b, 0xfa, 0x9b, 0x07}, + {0xf4, 0x0d, 0x30, 0xda, 0x51, 0x3a, 0x90, 0xe3, 0xb0, 0x5a, 0xa9, 0x3d, 0x23, 0x64, + 0x39, 0x84, 0x80, 0x64, 0x35, 0x0b, 0x2d, 0xf1, 0x3c, 0xed, 0x94, 0x71, 0x81, 0x84, + 0xf6, 0x77, 0x8c, 0x03, 0x45, 0x42, 0xd5, 0xa2, 0x80, 0xed, 0xc9, 0xf3, 0x52, 0x39, + 0xf6, 0x77, 0x78, 0x8b, 0xa0, 0x0a, 0x75, 0x54, 0x08, 0xd1, 0x63, 0xac, 0x6d, 0xd7, + 0x6b, 0x63, 0x70, 0x94, 0x15, 0xfb, 0xf4, 0x1e, 0xec, 0x7b, 0x16, 0x5b, 0xe6, 0x5e, + 0x4e, 0x85, 0xc2, 0xcd, 0xd0, 0x96, 0x42, 0x0a, 0x59, 0x59, 0x99, 0x21, 0x10, 0x98, + 0x34, 0xdf, 0xb2, 0x72, 0x56, 0xff, 0x0b, 0x4a, 0x2a, 0xe9, 0x5e, 0x57}, + {0xcf, 0x2f, 0x18, 0x8a, 0x90, 0x80, 0xc0, 0xd4, 0xbd, 0x9d, 0x48, 0x99, 0xc2, 0x70, + 0xe1, 0x30, 0xde, 0x33, 0xf7, 0x52, 0x57, 0xbd, 0xba, 0x05, 0x00, 0xfd, 0xd3, 0x2c, + 0x11, 0xe7, 0xd4, 0x43, 0x01, 0xd8, 0xa4, 0x0a, 0x45, 0xbc, 0x46, 0x5d, 0xd8, 0xb9, + 0x33, 0xa5, 0x27, 0x12, 0xaf, 0xc3, 0xc2, 0x06, 0x89, 0x2b, 0x26, 0x3b, 0x9e, 0x38, + 0x1b, 0x58, 0x2f, 0x38, 0x7e, 0x1e, 0x0a, 0x20, 0xc5, 0x3a, 0xf9, 0xea, 0x67, 0xb9, + 0x8d, 0x51, 0xc0, 0x52, 0x66, 0x05, 0x9b, 0x98, 0xbc, 0x71, 0xf5, 0x97, 0x71, 0x56, + 0xd9, 0x85, 0x2b, 0xfe, 0x38, 0x4e, 0x1e, 0x65, 0x52, 0xca, 0x0e, 0x05}, + {0x9c, 0x0c, 0x3f, 0x45, 0xde, 0x1a, 0x43, 0xc3, 0x9b, 0x3b, 0x70, 0xff, 0x5e, 0x04, + 0xf5, 0xe9, 0x3d, 0x7b, 0x84, 0xed, 0xc9, 0x7a, 0xd9, 0xfc, 0xc6, 0xf4, 0x58, 0x1c, + 0xc2, 0xe6, 0x0e, 0x4b, 0xea, 0x68, 0xe6, 0x60, 0x76, 0x39, 0xac, 0x97, 0x97, 0xb4, + 0x3a, 0x15, 0xfe, 0xbb, 0x19, 0x9b, 0x9f, 0xa7, 0xec, 0x34, 0xb5, 0x79, 0xb1, 0x4c, + 0x57, 0xae, 0x31, 0xa1, 0x9f, 0xc0, 0x51, 0x61, 0x96, 0x5d, 0xf0, 0xfd, 0x0d, 0x5c, + 0xf5, 0x3a, 0x7a, 0xee, 0xb4, 0x2a, 0xe0, 0x2e, 0x26, 0xdd, 0x09, 0x17, 0x17, 0x12, + 0x87, 0xbb, 0xb2, 0x11, 0x0b, 0x03, 0x0f, 0x80, 0xfa, 0x24, 0xef, 0x1f}, + {0x96, 0x31, 0xa7, 0x1a, 0xfb, 0x53, 0xd6, 0x37, 0x18, 0x64, 0xd7, 0x3f, 0x30, 0x95, + 0x94, 0x0f, 0xb2, 0x17, 0x3a, 0xfb, 0x09, 0x0b, 0x20, 0xad, 0x3e, 0x61, 0xc8, 0x2f, + 0x29, 0x49, 0x4d, 0x54, 0x86, 0x6b, 0x97, 0x30, 0xf5, 0xaf, 0xd2, 0x22, 0x04, 0x46, + 0xd2, 0xc2, 0x06, 0xb8, 0x90, 0x8d, 0xe5, 0xba, 0xe5, 0x4d, 0x6c, 0x89, 0xa1, 0xdc, + 0x17, 0x0c, 0x34, 0xc8, 0xe6, 0x5f, 0x00, 0x28, 0x88, 0x86, 0x52, 0x34, 0x9f, 0xba, + 0xef, 0x6a, 0xa1, 0x7d, 0x10, 0x25, 0x94, 0xff, 0x1b, 0x5c, 0x36, 0x4b, 0xd9, 0x66, + 0xcd, 0xbb, 0x5b, 0xf7, 0xfa, 0x6d, 0x31, 0x0f, 0x93, 0x72, 0xe4, 0x72}, + {0x4f, 0x08, 0x81, 0x97, 0x8c, 0x20, 0x95, 0x26, 0xe1, 0x0e, 0x45, 0x23, 0x0b, 0x2a, + 0x50, 0xb1, 0x02, 0xde, 0xef, 0x03, 0xa6, 0xae, 0x9d, 0xfd, 0x4c, 0xa3, 0x33, 0x27, + 0x8c, 0x2e, 0x9d, 0x5a, 0x27, 0x76, 0x2a, 0xd3, 0x35, 0xf6, 0xf3, 0x07, 0xf0, 0x66, + 0x65, 0x5f, 0x86, 0x4d, 0xaa, 0x7a, 0x50, 0x44, 0xd0, 0x28, 0x97, 0xe7, 0x85, 0x3c, + 0x38, 0x64, 0xe0, 0x0f, 0x00, 0x7f, 0xee, 0x1f, 0xe5, 0xf7, 0xdb, 0x03, 0xda, 0x05, + 0x53, 0x76, 0xbd, 0xcd, 0x34, 0x14, 0x49, 0xf2, 0xda, 0xa4, 0xec, 0x88, 0x4a, 0xd2, + 0xcd, 0xd5, 0x4a, 0x7b, 0x43, 0x05, 0x04, 0xee, 0x51, 0x40, 0xf9, 0x00}, + {0xb2, 0x30, 0xd3, 0xc3, 0x23, 0x6b, 0x35, 0x8d, 0x06, 0x1b, 0x47, 0xb0, 0x9b, 0x8b, + 0x1c, 0xf2, 0x3c, 0xb8, 0x42, 0x6e, 0x6c, 0x31, 0x6c, 0xb3, 0x0d, 0xb1, 0xea, 0x8b, + 0x7e, 0x9c, 0xd7, 0x07, 0x53, 0x97, 0xaf, 0x07, 0xbb, 0x93, 0xef, 0xd7, 0xa7, 0x66, + 0xb7, 0x3d, 0xcf, 0xd0, 0x3e, 0x58, 0xc5, 0x1e, 0x0b, 0x6e, 0xbf, 0x98, 0x69, 0xce, + 0x52, 0x04, 0xd4, 0x5d, 0xd2, 0xff, 0xb7, 0x47, 0x12, 0xdd, 0x08, 0xbc, 0x9c, 0xfb, + 0xfb, 0x87, 0x9b, 0xc2, 0xee, 0xe1, 0x3a, 0x6b, 0x06, 0x8a, 0xbf, 0xc1, 0x1f, 0xdb, + 0x2b, 0x24, 0x57, 0x0d, 0xb6, 0x4b, 0xa6, 0x5e, 0xa3, 0x20, 0x35, 0x1c}, + {0x4a, 0xa3, 0xcb, 0xbc, 0xa6, 0x53, 0xd2, 0x80, 0x9b, 0x21, 0x38, 0x38, 0xa1, 0xc3, + 0x61, 0x3e, 0x96, 0xe3, 0x82, 0x98, 0x01, 0xb6, 0xc3, 0x90, 0x6f, 0xe6, 0x0e, 0x5d, + 0x77, 0x05, 0x3d, 0x1c, 0x59, 0xc0, 0x6b, 0x21, 0x40, 0x6f, 0xa8, 0xcd, 0x7e, 0xd8, + 0xbc, 0x12, 0x1d, 0x23, 0xbb, 0x1f, 0x90, 0x09, 0xc7, 0x17, 0x9e, 0x6a, 0x95, 0xb4, + 0x55, 0x2e, 0xd1, 0x66, 0x3b, 0x0c, 0x75, 0x38, 0x1a, 0xe5, 0x22, 0x94, 0x40, 0xf1, + 0x2e, 0x69, 0x71, 0xf6, 0x5d, 0x2b, 0x3c, 0xc7, 0xc0, 0xcb, 0x29, 0xe0, 0x4c, 0x74, + 0xe7, 0x4f, 0x01, 0x21, 0x7c, 0x48, 0x30, 0xd3, 0xc7, 0xe2, 0x21, 0x06}, + {0x8d, 0x83, 0x59, 0x82, 0xcc, 0x60, 0x98, 0xaf, 0xdc, 0x9a, 0x9f, 0xc6, 0xc1, 0x48, + 0xea, 0x90, 0x30, 0x1e, 0x58, 0x65, 0x37, 0x48, 0x26, 0x65, 0xbc, 0xa5, 0xd3, 0x7b, + 0x09, 0xd6, 0x07, 0x00, 0xf3, 0xf0, 0xdb, 0xb0, 0x96, 0x17, 0xae, 0xb7, 0x96, 0xe1, + 0x7c, 0xe1, 0xb9, 0xaf, 0xdf, 0x54, 0xb4, 0xa3, 0xaa, 0xe9, 0x71, 0x30, 0x92, 0x25, + 0x9d, 0x2e, 0x00, 0xa1, 0x9c, 0x58, 0x8e, 0x5d, 0x4b, 0xa9, 0x42, 0x08, 0x95, 0x1d, + 0xbf, 0xc0, 0x3e, 0x2e, 0x8f, 0x58, 0x63, 0xc3, 0xd3, 0xb2, 0xef, 0xe2, 0x51, 0xbb, + 0x38, 0x14, 0x96, 0x0a, 0x86, 0xbf, 0x1c, 0x3c, 0x78, 0xd7, 0x83, 0x15}, + {0xe1, 0x7a, 0xa2, 0x5d, 0xef, 0xa2, 0xee, 0xec, 0x74, 0x01, 0x67, 0x55, 0x14, 0x3a, + 0x7c, 0x59, 0x7a, 0x16, 0x09, 0x66, 0x12, 0x2a, 0xa6, 0xc9, 0x70, 0x8f, 0xed, 0x81, + 0x2e, 0x5f, 0x2a, 0x25, 0xc7, 0x28, 0x9d, 0xcc, 0x04, 0x47, 0x03, 0x90, 0x8f, 0xc5, + 0x2c, 0xf7, 0x9e, 0x67, 0x1b, 0x1d, 0x26, 0x87, 0x5b, 0xbe, 0x5f, 0x2b, 0xe1, 0x16, + 0x0a, 0x58, 0xc5, 0x83, 0x4e, 0x06, 0x58, 0x49, 0x0d, 0xe8, 0x66, 0x50, 0x26, 0x94, + 0x28, 0x0d, 0x6b, 0x8c, 0x7c, 0x30, 0x85, 0xf7, 0xc3, 0xfc, 0xfd, 0x12, 0x11, 0x0c, + 0x78, 0xda, 0x53, 0x1b, 0x88, 0xb3, 0x43, 0xd8, 0x0b, 0x17, 0x9c, 0x07}, + {0xff, 0x6f, 0xfa, 0x64, 0xe4, 0xec, 0x06, 0x05, 0x23, 0xe5, 0x05, 0x62, 0x1e, 0x43, + 0xe3, 0xbe, 0x42, 0xea, 0xb8, 0x51, 0x24, 0x42, 0x79, 0x35, 0x00, 0xfb, 0xc9, 0x4a, + 0xe3, 0x05, 0xec, 0x6d, 0x56, 0xd0, 0xd5, 0xc0, 0x50, 0xcd, 0xd6, 0xcd, 0x3b, 0x57, + 0x03, 0xbb, 0x6d, 0x68, 0xf7, 0x9a, 0x48, 0xef, 0xc3, 0xf3, 0x3f, 0x72, 0xa6, 0x3c, + 0xcc, 0x8a, 0x7b, 0x31, 0xd7, 0xc0, 0x68, 0x67, 0xb3, 0xc1, 0x55, 0xf1, 0xe5, 0x25, + 0xb6, 0x94, 0x91, 0x7b, 0x7b, 0x99, 0xa7, 0xf3, 0x7b, 0x41, 0x00, 0x26, 0x6b, 0x6d, + 0xdc, 0xbd, 0x2c, 0xc2, 0xf4, 0x52, 0xcd, 0xdd, 0x14, 0x5e, 0x44, 0x51}, + {0x51, 0x49, 0x14, 0x3b, 0x4b, 0x2b, 0x50, 0x57, 0xb3, 0xbc, 0x4b, 0x44, 0x6b, 0xff, + 0x67, 0x8e, 0xdb, 0x85, 0x63, 0x16, 0x27, 0x69, 0xbd, 0xb8, 0xc8, 0x95, 0x92, 0xe3, + 0x31, 0x6f, 0x18, 0x13, 0x55, 0xa4, 0xbe, 0x2b, 0xab, 0x47, 0x31, 0x89, 0x29, 0x91, + 0x07, 0x92, 0x4f, 0xa2, 0x53, 0x8c, 0xa7, 0xf7, 0x30, 0xbe, 0x48, 0xf9, 0x49, 0x4b, + 0x3d, 0xd4, 0x4f, 0x6e, 0x08, 0x90, 0xe9, 0x12, 0x2e, 0xbb, 0xdf, 0x7f, 0xb3, 0x96, + 0x0c, 0xf1, 0xf9, 0xea, 0x1c, 0x12, 0x5e, 0x93, 0x9a, 0x9f, 0x3f, 0x98, 0x5b, 0x3a, + 0xc4, 0x36, 0x11, 0xdf, 0xaf, 0x99, 0x3e, 0x5d, 0xf0, 0xe3, 0xb2, 0x77}, + {0xde, 0xc4, 0x2e, 0x9c, 0xc5, 0xa9, 0x6f, 0x29, 0xcb, 0xf3, 0x84, 0x4f, 0xbf, 0x61, + 0x8b, 0xbc, 0x08, 0xf9, 0xa8, 0x17, 0xd9, 0x06, 0x77, 0x1c, 0x5d, 0x25, 0xd3, 0x7a, + 0xfc, 0x95, 0xb7, 0x63, 0xa4, 0xb0, 0xdd, 0x12, 0x9c, 0x63, 0x98, 0xd5, 0x6b, 0x86, + 0x24, 0xc0, 0x30, 0x9f, 0xd1, 0xa5, 0x60, 0xe4, 0xfc, 0x58, 0x03, 0x2f, 0x7c, 0xd1, + 0x8a, 0x5e, 0x09, 0x2e, 0x15, 0x95, 0xa1, 0x07, 0xc8, 0x5f, 0x9e, 0x38, 0x02, 0x8f, + 0x36, 0xa8, 0x3b, 0xe4, 0x8d, 0xcf, 0x02, 0x3b, 0x43, 0x90, 0x43, 0x26, 0x41, 0xc5, + 0x5d, 0xfd, 0xa1, 0xaf, 0x37, 0x01, 0x2f, 0x03, 0x3d, 0xe8, 0x8f, 0x3e}, + {0x94, 0xa2, 0x70, 0x05, 0xb9, 0x15, 0x8b, 0x2f, 0x49, 0x45, 0x08, 0x67, 0x70, 0x42, + 0xf2, 0x94, 0x84, 0xfd, 0xbb, 0x61, 0xe1, 0x5a, 0x1c, 0xde, 0x07, 0x40, 0xac, 0x7f, + 0x79, 0x3b, 0xba, 0x75, 0x3c, 0xd1, 0xef, 0xe8, 0x8d, 0x4c, 0x70, 0x08, 0x31, 0x37, + 0xe0, 0x33, 0x8e, 0x1a, 0xc5, 0xdf, 0xe3, 0xcd, 0x60, 0x12, 0xa5, 0x5d, 0x9d, 0xa5, + 0x86, 0x8c, 0x25, 0xa6, 0x99, 0x08, 0xd6, 0x22, 0x96, 0xd1, 0xcd, 0x70, 0xc0, 0xdb, + 0x39, 0x62, 0x9a, 0x8a, 0x7d, 0x6c, 0x8b, 0x8a, 0xfe, 0x60, 0x60, 0x12, 0x40, 0xeb, + 0xbc, 0x47, 0x88, 0xb3, 0x5e, 0x9e, 0x77, 0x87, 0x7b, 0xd0, 0x04, 0x09}, + {0x9c, 0x91, 0xba, 0xdd, 0xd4, 0x1f, 0xce, 0xb4, 0xaa, 0x8d, 0x4c, 0xc7, 0x3e, 0xdb, + 0x31, 0xcf, 0x51, 0xcc, 0x86, 0xad, 0x63, 0xcc, 0x63, 0x2c, 0x07, 0xde, 0x1d, 0xbc, + 0x3f, 0x14, 0xe2, 0x43, 0xb9, 0x40, 0xf9, 0x48, 0x66, 0x2d, 0x32, 0xf4, 0x39, 0x0c, + 0x2d, 0xbd, 0x0c, 0x2f, 0x95, 0x06, 0x31, 0xf9, 0x81, 0xa0, 0xad, 0x97, 0x76, 0x16, + 0x6c, 0x2a, 0xf7, 0xba, 0xce, 0xaa, 0x40, 0x62, 0xa0, 0x95, 0xa2, 0x5b, 0x9c, 0x74, + 0x34, 0xf8, 0x5a, 0xd2, 0x37, 0xca, 0x5b, 0x7c, 0x94, 0xd6, 0x6a, 0x31, 0xc9, 0xe7, + 0xa7, 0x3b, 0xf1, 0x66, 0xac, 0x0c, 0xb4, 0x8d, 0x23, 0xaf, 0xbd, 0x56}, + {0xeb, 0x33, 0x35, 0xf5, 0xe3, 0xb9, 0x2a, 0x36, 0x40, 0x3d, 0xb9, 0x6e, 0xd5, 0x68, + 0x85, 0x33, 0x72, 0x55, 0x5a, 0x1d, 0x52, 0x14, 0x0e, 0x9e, 0x18, 0x13, 0x74, 0x83, + 0x6d, 0xa8, 0x24, 0x1d, 0xb2, 0x3b, 0x9d, 0xc1, 0x6c, 0xd3, 0x10, 0x13, 0xb9, 0x86, + 0x23, 0x62, 0xb7, 0x6b, 0x2a, 0x06, 0x5c, 0x4f, 0xa1, 0xd7, 0x91, 0x85, 0x9b, 0x7c, + 0x54, 0x57, 0x1e, 0x7e, 0x50, 0x31, 0xaa, 0x03, 0x1f, 0xce, 0xd4, 0xff, 0x48, 0x76, + 0xec, 0xf4, 0x1c, 0x8c, 0xac, 0x54, 0xf0, 0xea, 0x45, 0xe0, 0x7c, 0x35, 0x09, 0x1d, + 0x82, 0x25, 0xd2, 0x88, 0x59, 0x48, 0xeb, 0x9a, 0xdc, 0x61, 0xb2, 0x43}, + {0xbb, 0x79, 0xbb, 0x88, 0x19, 0x1e, 0x5b, 0xe5, 0x9d, 0x35, 0x7a, 0xc1, 0x7d, 0xd0, + 0x9e, 0xa0, 0x33, 0xea, 0x3d, 0x60, 0xe2, 0x2e, 0x2c, 0xb0, 0xc2, 0x6b, 0x27, 0x5b, + 0xcf, 0x55, 0x60, 0x32, 0x64, 0x13, 0x95, 0x6c, 0x8b, 0x3d, 0x51, 0x19, 0x7b, 0xf4, + 0x0b, 0x00, 0x26, 0x71, 0xfe, 0x94, 0x67, 0x95, 0x4f, 0xd5, 0xdd, 0x10, 0x8d, 0x02, + 0x64, 0x09, 0x94, 0x42, 0xe2, 0xd5, 0xb4, 0x02, 0xf2, 0x8d, 0xd1, 0x28, 0xcb, 0x55, + 0xa1, 0xb4, 0x08, 0xe5, 0x6c, 0x18, 0x46, 0x46, 0xcc, 0xea, 0x89, 0x43, 0x82, 0x6c, + 0x93, 0xf4, 0x9c, 0xc4, 0x10, 0x34, 0x5d, 0xae, 0x09, 0xc8, 0xa6, 0x27}, + {0x88, 0xb1, 0x0d, 0x1f, 0xcd, 0xeb, 0xa6, 0x8b, 0xe8, 0x5b, 0x5a, 0x67, 0x3a, 0xd7, + 0xd3, 0x37, 0x5a, 0x58, 0xf5, 0x15, 0xa3, 0xdf, 0x2e, 0xf2, 0x7e, 0xa1, 0x60, 0xff, + 0x74, 0x71, 0xb6, 0x2c, 0x54, 0x69, 0x3d, 0xc4, 0x0a, 0x27, 0x2c, 0xcd, 0xb2, 0xca, + 0x66, 0x6a, 0x57, 0x3e, 0x4a, 0xdd, 0x6c, 0x03, 0xd7, 0x69, 0x24, 0x59, 0xfa, 0x79, + 0x99, 0x25, 0x8c, 0x3d, 0x60, 0x03, 0x15, 0x22, 0xd0, 0xe1, 0x0b, 0x39, 0xf9, 0xcd, + 0xee, 0x59, 0xf1, 0xe3, 0x8c, 0x72, 0x44, 0x20, 0x42, 0xa9, 0xf4, 0xf0, 0x94, 0x7a, + 0x66, 0x1c, 0x89, 0x82, 0x36, 0xf4, 0x90, 0x38, 0xb7, 0xf4, 0x1d, 0x7b}, + {0x24, 0xa2, 0xb2, 0xb3, 0xe0, 0xf2, 0x92, 0xe4, 0x60, 0x11, 0x55, 0x2b, 0x06, 0x9e, + 0x6c, 0x7c, 0x0e, 0x7b, 0x7f, 0x0d, 0xe2, 0x8f, 0xeb, 0x15, 0x92, 0x59, 0xfc, 0x58, + 0x26, 0xef, 0xfc, 0x61, 0x8c, 0xf5, 0xf8, 0x07, 0x18, 0x22, 0x2e, 0x5f, 0xd4, 0x09, + 0x94, 0xd4, 0x9f, 0x5c, 0x55, 0xe3, 0x30, 0xa6, 0xb6, 0x1f, 0x8d, 0xa8, 0xaa, 0xb2, + 0x3d, 0xe0, 0x52, 0xd3, 0x45, 0x82, 0x69, 0x68, 0x7a, 0x18, 0x18, 0x2a, 0x85, 0x5d, + 0xb1, 0xdb, 0xd7, 0xac, 0xdd, 0x86, 0xd3, 0xaa, 0xe4, 0xf3, 0x82, 0xc4, 0xf6, 0x0f, + 0x81, 0xe2, 0xba, 0x44, 0xcf, 0x01, 0xaf, 0x3d, 0x47, 0x4c, 0xcf, 0x46}, + {0xf9, 0xe5, 0xc4, 0x9e, 0xed, 0x25, 0x65, 0x42, 0x03, 0x33, 0x90, 0x16, 0x01, 0xda, + 0x5e, 0x0e, 0xdc, 0xca, 0xe5, 0xcb, 0xf2, 0xa7, 0xb1, 0x72, 0x40, 0x5f, 0xeb, 0x14, + 0xcd, 0x7b, 0x38, 0x29, 0x40, 0x81, 0x49, 0xf1, 0xa7, 0x6e, 0x3c, 0x21, 0x54, 0x48, + 0x2b, 0x39, 0xf8, 0x7e, 0x1e, 0x7c, 0xba, 0xce, 0x29, 0x56, 0x8c, 0xc3, 0x88, 0x24, + 0xbb, 0xc5, 0x8c, 0x0d, 0xe5, 0xaa, 0x65, 0x10, 0x57, 0x0d, 0x20, 0xdf, 0x25, 0x45, + 0x2c, 0x1c, 0x4a, 0x67, 0xca, 0xbf, 0xd6, 0x2d, 0x3b, 0x5c, 0x30, 0x40, 0x83, 0xe1, + 0xb1, 0xe7, 0x07, 0x0a, 0x16, 0xe7, 0x1c, 0x4f, 0xe6, 0x98, 0xa1, 0x69}, + {0xbc, 0x78, 0x1a, 0xd9, 0xe0, 0xb2, 0x62, 0x90, 0x67, 0x96, 0x50, 0xc8, 0x9c, 0x88, + 0xc9, 0x47, 0xb8, 0x70, 0x50, 0x40, 0x66, 0x4a, 0xf5, 0x9d, 0xbf, 0xa1, 0x93, 0x24, + 0xa9, 0xe6, 0x69, 0x73, 0xed, 0xca, 0xc5, 0xdc, 0x34, 0x44, 0x01, 0xe1, 0x33, 0xfb, + 0x84, 0x3c, 0x96, 0x5d, 0xed, 0x47, 0xe7, 0xa0, 0x86, 0xed, 0x76, 0x95, 0x01, 0x70, + 0xe4, 0xf9, 0x67, 0xd2, 0x7b, 0x69, 0xb2, 0x25, 0x64, 0x68, 0x98, 0x13, 0xfb, 0x3f, + 0x67, 0x9d, 0xb8, 0xc7, 0x5d, 0x41, 0xd9, 0xfb, 0xa5, 0x3c, 0x5e, 0x3b, 0x27, 0xdf, + 0x3b, 0xcc, 0x4e, 0xe0, 0xd2, 0x4c, 0x4e, 0xb5, 0x3d, 0x68, 0x20, 0x14}, + {0x97, 0xd1, 0x9d, 0x24, 0x1e, 0xbd, 0x78, 0xb4, 0x02, 0xc1, 0x58, 0x5e, 0x00, 0x35, + 0x0c, 0x62, 0x5c, 0xac, 0xba, 0xcc, 0x2f, 0xd3, 0x02, 0xfb, 0x2d, 0xa7, 0x08, 0xf5, + 0xeb, 0x3b, 0xb6, 0x60, 0xd0, 0x5a, 0xcc, 0xc1, 0x6f, 0xbb, 0xee, 0x34, 0x8b, 0xac, + 0x46, 0x96, 0xe9, 0x0c, 0x1b, 0x6a, 0x53, 0xde, 0x6b, 0xa6, 0x49, 0xda, 0xb0, 0xd3, + 0xc1, 0x81, 0xd0, 0x61, 0x41, 0x3b, 0xe8, 0x31, 0x4f, 0x2b, 0x06, 0x9e, 0x12, 0xc7, + 0xe8, 0x97, 0xd8, 0x0a, 0x32, 0x29, 0x4f, 0x8f, 0xe4, 0x49, 0x3f, 0x68, 0x18, 0x6f, + 0x4b, 0xe1, 0xec, 0x5b, 0x17, 0x03, 0x55, 0x2d, 0xb6, 0x1e, 0xcf, 0x55}, + {0x58, 0x3d, 0xc2, 0x65, 0x10, 0x10, 0x79, 0x58, 0x9c, 0x81, 0x94, 0x50, 0x6d, 0x08, + 0x9d, 0x8b, 0xa7, 0x5f, 0xc5, 0x12, 0xa9, 0x2f, 0x40, 0xe2, 0xd4, 0x91, 0x08, 0x57, + 0x64, 0x65, 0x9a, 0x66, 0x52, 0x8c, 0xf5, 0x7d, 0xe3, 0xb5, 0x76, 0x30, 0x36, 0xcc, + 0x99, 0xe7, 0xdd, 0xb9, 0x3a, 0xd7, 0x20, 0xee, 0x13, 0x49, 0xe3, 0x1c, 0x83, 0xbd, + 0x33, 0x01, 0xba, 0x62, 0xaa, 0xfb, 0x56, 0x1a, 0xec, 0xc9, 0x9d, 0x5c, 0x50, 0x6b, + 0x3e, 0x94, 0x1a, 0x37, 0x7c, 0xa7, 0xbb, 0x57, 0x25, 0x30, 0x51, 0x76, 0x34, 0x41, + 0x56, 0xae, 0x73, 0x98, 0x5c, 0x8a, 0xc5, 0x99, 0x67, 0x83, 0xc4, 0x13}, + {0xb9, 0xe1, 0xb3, 0x5a, 0x46, 0x5d, 0x3a, 0x42, 0x61, 0x3f, 0xf1, 0xc7, 0x87, 0xc1, + 0x13, 0xfc, 0xb6, 0xb9, 0xb5, 0xec, 0x64, 0x36, 0xf8, 0x19, 0x07, 0xb6, 0x37, 0xa6, + 0x93, 0x0c, 0xf8, 0x66, 0x80, 0xd0, 0x8b, 0x5d, 0x6a, 0xfb, 0xdc, 0xc4, 0x42, 0x48, + 0x1a, 0x57, 0xec, 0xc4, 0xeb, 0xde, 0x65, 0x53, 0xe5, 0xb8, 0x83, 0xe8, 0xb2, 0xd4, + 0x27, 0xb8, 0xe5, 0xc8, 0x7d, 0xc8, 0xbd, 0x50, 0x11, 0xe1, 0xdf, 0x6e, 0x83, 0x37, + 0x6d, 0x60, 0xd9, 0xab, 0x11, 0xf0, 0x15, 0x3e, 0x35, 0x32, 0x96, 0x3b, 0xb7, 0x25, + 0xc3, 0x3a, 0xb0, 0x64, 0xae, 0xd5, 0x5f, 0x72, 0x44, 0x64, 0xd5, 0x1d}, + {0x7d, 0x12, 0x62, 0x33, 0xf8, 0x7f, 0xa4, 0x8f, 0x15, 0x7c, 0xcd, 0x71, 0xc4, 0x6a, + 0x9f, 0xbc, 0x8b, 0x0c, 0x22, 0x49, 0x43, 0x45, 0x71, 0x6e, 0x2e, 0x73, 0x9f, 0x21, + 0x12, 0x59, 0x64, 0x0e, 0x9a, 0xc8, 0xba, 0x08, 0x00, 0xe6, 0x97, 0xc2, 0xe0, 0xc3, + 0xe1, 0xea, 0x11, 0xea, 0x4c, 0x7d, 0x7c, 0x97, 0xe7, 0x9f, 0xe1, 0x8b, 0xe3, 0xf3, + 0xcd, 0x05, 0xa3, 0x63, 0x0f, 0x45, 0x3a, 0x3a, 0x27, 0x46, 0x39, 0xd8, 0x31, 0x2f, + 0x8f, 0x07, 0x10, 0xa5, 0x94, 0xde, 0x83, 0x31, 0x9d, 0x38, 0x80, 0x6f, 0x99, 0x17, + 0x6d, 0x6c, 0xe3, 0xd1, 0x7b, 0xa8, 0xa9, 0x93, 0x93, 0x8d, 0x8c, 0x31}, + {0x19, 0xfe, 0xff, 0x2a, 0x03, 0x5d, 0x74, 0xf2, 0x66, 0xdb, 0x24, 0x7f, 0x49, 0x3c, + 0x9f, 0x0c, 0xef, 0x98, 0x85, 0xba, 0xe3, 0xd3, 0x98, 0xbc, 0x14, 0x53, 0x1d, 0x9a, + 0x67, 0x7c, 0x4c, 0x22, 0x98, 0xd3, 0x1d, 0xab, 0x29, 0x9e, 0x66, 0x5d, 0x3b, 0x9e, + 0x2d, 0x34, 0x58, 0x16, 0x92, 0xfc, 0xcd, 0x73, 0x59, 0xf3, 0xfd, 0x1d, 0x85, 0x55, + 0xf6, 0x0a, 0x95, 0x25, 0xc3, 0x41, 0x9a, 0x50, 0xe9, 0x25, 0xf9, 0xa6, 0xdc, 0x6e, + 0xc0, 0xbd, 0x33, 0x1f, 0x1b, 0x64, 0xf4, 0xf3, 0x3e, 0x79, 0x89, 0x3e, 0x83, 0x9d, + 0x80, 0x12, 0xec, 0x82, 0x89, 0x13, 0xa1, 0x28, 0x23, 0xf0, 0xbf, 0x05}, + {0x0b, 0xe0, 0xca, 0x23, 0x70, 0x13, 0x32, 0x36, 0x59, 0xcf, 0xac, 0xd1, 0x0a, 0xcf, + 0x4a, 0x54, 0x88, 0x1c, 0x1a, 0xd2, 0x49, 0x10, 0x74, 0x96, 0xa7, 0x44, 0x2a, 0xfa, + 0xc3, 0x8c, 0x0b, 0x78, 0xe4, 0x12, 0xc5, 0x0d, 0xdd, 0xa0, 0x81, 0x68, 0xfe, 0xfa, + 0xa5, 0x44, 0xc8, 0x0d, 0xe7, 0x4f, 0x40, 0x52, 0x4a, 0x8f, 0x6b, 0x8e, 0x74, 0x1f, + 0xea, 0xa3, 0x01, 0xee, 0xcd, 0x77, 0x62, 0x57, 0x5f, 0x30, 0x4f, 0x23, 0xbc, 0x8a, + 0xf3, 0x1e, 0x08, 0xde, 0x05, 0x14, 0xbd, 0x7f, 0x57, 0x9a, 0x0d, 0x2a, 0xe6, 0x34, + 0x14, 0xa5, 0x82, 0x5e, 0xa1, 0xb7, 0x71, 0x62, 0x72, 0x18, 0xf4, 0x5f}, + {0x9d, 0xdb, 0x89, 0x17, 0x0c, 0x08, 0x8e, 0x39, 0xf5, 0x78, 0xe7, 0xf3, 0x25, 0x20, + 0x60, 0xa7, 0x5d, 0x03, 0xbd, 0x06, 0x4c, 0x89, 0x98, 0xfa, 0xbe, 0x66, 0xa9, 0x25, + 0xdc, 0x03, 0x6a, 0x10, 0x40, 0x95, 0xb6, 0x13, 0xe8, 0x47, 0xdb, 0xe5, 0xe1, 0x10, + 0x26, 0x43, 0x3b, 0x2a, 0x5d, 0xf3, 0x76, 0x12, 0x78, 0x38, 0xe9, 0x26, 0x1f, 0xac, + 0x69, 0xcb, 0xa0, 0xa0, 0x8c, 0xdb, 0xd4, 0x29, 0xd0, 0x53, 0x33, 0x33, 0xaf, 0x0a, + 0xad, 0xd9, 0xe5, 0x09, 0xd3, 0xac, 0xa5, 0x9d, 0x66, 0x38, 0xf0, 0xf7, 0x88, 0xc8, + 0x8a, 0x65, 0x57, 0x3c, 0xfa, 0xbe, 0x2c, 0x05, 0x51, 0x8a, 0xb3, 0x4a}, + {0x93, 0xd5, 0x68, 0x67, 0x25, 0x2b, 0x7c, 0xda, 0x13, 0xca, 0x22, 0x44, 0x57, 0xc0, + 0xc1, 0x98, 0x1d, 0xce, 0x0a, 0xca, 0xd5, 0x0b, 0xa8, 0xf1, 0x90, 0xa6, 0x88, 0xc0, + 0xad, 0xd1, 0xcd, 0x29, 0x9c, 0xc0, 0xdd, 0x5f, 0xef, 0xd1, 0xcf, 0xd6, 0xce, 0x5d, + 0x57, 0xf7, 0xfd, 0x3e, 0x2b, 0xe8, 0xc2, 0x34, 0x16, 0x20, 0x5d, 0x6b, 0xd5, 0x25, + 0x9b, 0x2b, 0xed, 0x04, 0xbb, 0xc6, 0x41, 0x30, 0x48, 0xe1, 0x56, 0xd9, 0xf9, 0xf2, + 0xf2, 0x0f, 0x2e, 0x6b, 0x35, 0x9f, 0x75, 0x97, 0xe7, 0xad, 0x5c, 0x02, 0x6c, 0x5f, + 0xbb, 0x98, 0x46, 0x1a, 0x7b, 0x9a, 0x04, 0x14, 0x68, 0xbd, 0x4b, 0x10}, + {0x67, 0xed, 0xf1, 0x68, 0x31, 0xfd, 0xf0, 0x51, 0xc2, 0x3b, 0x6f, 0xd8, 0xcd, 0x1d, + 0x81, 0x2c, 0xde, 0xf2, 0xd2, 0x04, 0x43, 0x5c, 0xdc, 0x44, 0x49, 0x71, 0x2a, 0x09, + 0x57, 0xcc, 0xe8, 0x5b, 0x63, 0xf1, 0x7f, 0xd6, 0x5f, 0x9a, 0x5d, 0xa9, 0x81, 0x56, + 0xc7, 0x4c, 0x9d, 0xe6, 0x2b, 0xe9, 0x57, 0xf2, 0x20, 0xde, 0x4c, 0x02, 0xf8, 0xb7, + 0xf5, 0x2d, 0x07, 0xfb, 0x20, 0x2a, 0x4f, 0x20, 0x79, 0xb0, 0xeb, 0x30, 0x3d, 0x3b, + 0x14, 0xc8, 0x30, 0x2e, 0x65, 0xbd, 0x5a, 0x15, 0x89, 0x75, 0x31, 0x5c, 0x6d, 0x8f, + 0x31, 0x3c, 0x3c, 0x65, 0x1f, 0x16, 0x79, 0xc2, 0x17, 0xfb, 0x70, 0x25}, + {0x75, 0x15, 0xb6, 0x2c, 0x7f, 0x36, 0xfa, 0x3e, 0x6c, 0x02, 0xd6, 0x1c, 0x76, 0x6f, + 0xf9, 0xf5, 0x62, 0x25, 0xb5, 0x65, 0x2a, 0x14, 0xc7, 0xe8, 0xcd, 0x0a, 0x03, 0x53, + 0xea, 0x65, 0xcb, 0x3d, 0x5a, 0x24, 0xb8, 0x0b, 0x55, 0xa9, 0x2e, 0x19, 0xd1, 0x50, + 0x90, 0x8f, 0xa8, 0xfb, 0xe6, 0xc8, 0x35, 0xc9, 0xa4, 0x88, 0x2d, 0xea, 0x86, 0x79, + 0x68, 0x86, 0x01, 0xde, 0x91, 0x5f, 0x1c, 0x24, 0xaa, 0x6c, 0xde, 0x40, 0x29, 0x17, + 0xd8, 0x28, 0x3a, 0x73, 0xd9, 0x22, 0xf0, 0x2c, 0xbf, 0x8f, 0xd1, 0x01, 0x5b, 0x23, + 0xdd, 0xfc, 0xd7, 0x16, 0xe5, 0xf0, 0xcd, 0x5f, 0xdd, 0x0e, 0x42, 0x08}, + {0x4a, 0xfa, 0x62, 0x83, 0xab, 0x20, 0xff, 0xcd, 0x6e, 0x3e, 0x1a, 0xe2, 0xd4, 0x18, + 0xe1, 0x57, 0x2b, 0xe6, 0x39, 0xfc, 0x17, 0x96, 0x17, 0xe3, 0xfd, 0x69, 0x17, 0xbc, + 0xef, 0x53, 0x9a, 0x0d, 0xce, 0x10, 0xf4, 0x04, 0x4e, 0xc3, 0x58, 0x03, 0x85, 0x06, + 0x6e, 0x27, 0x5a, 0x5b, 0x13, 0xb6, 0x21, 0x15, 0xb9, 0xeb, 0xc7, 0x70, 0x96, 0x5d, + 0x9c, 0x88, 0xdb, 0x21, 0xf3, 0x54, 0xd6, 0x04, 0xd5, 0xb5, 0xbd, 0xdd, 0x16, 0xc1, + 0x7d, 0x5e, 0x2d, 0xdd, 0xa5, 0x8d, 0xb6, 0xde, 0x54, 0x29, 0x92, 0xa2, 0x34, 0x33, + 0x17, 0x08, 0xb6, 0x1c, 0xd7, 0x1a, 0x99, 0x18, 0x26, 0x4f, 0x7a, 0x4a}, + {0x95, 0x5f, 0xb1, 0x5f, 0x02, 0x18, 0xa7, 0xf4, 0x8f, 0x1b, 0x5c, 0x6b, 0x34, 0x5f, + 0xf6, 0x3d, 0x12, 0x11, 0xe0, 0x00, 0x85, 0xf0, 0xfc, 0xcd, 0x48, 0x18, 0xd3, 0xdd, + 0x4c, 0x0c, 0xb5, 0x11, 0x4b, 0x2a, 0x37, 0xaf, 0x91, 0xb2, 0xc3, 0x24, 0xf2, 0x47, + 0x81, 0x71, 0x70, 0x82, 0xda, 0x93, 0xf2, 0x9e, 0x89, 0x86, 0x64, 0x85, 0x84, 0xdd, + 0x33, 0xee, 0xe0, 0x23, 0x42, 0x31, 0x96, 0x4a, 0xd6, 0xff, 0xa4, 0x08, 0x44, 0x27, + 0xe8, 0xa6, 0xd9, 0x76, 0x15, 0x9c, 0x7e, 0x17, 0x8e, 0x73, 0xf2, 0xb3, 0x02, 0x3d, + 0xb6, 0x48, 0x33, 0x77, 0x51, 0xcc, 0x6b, 0xce, 0x4d, 0xce, 0x4b, 0x4f}, + {0x84, 0x25, 0x24, 0xe2, 0x5a, 0xce, 0x1f, 0xa7, 0x9e, 0x8a, 0xf5, 0x92, 0x56, 0x72, + 0xea, 0x26, 0xf4, 0x3c, 0xea, 0x1c, 0xd7, 0x09, 0x1a, 0xd2, 0xe6, 0x01, 0x1c, 0xb7, + 0x14, 0xdd, 0xfc, 0x73, 0x6f, 0x0b, 0x9d, 0xc4, 0x6e, 0x61, 0xe2, 0x30, 0x17, 0x23, + 0xec, 0xca, 0x8f, 0x71, 0x56, 0xe4, 0xa6, 0x4f, 0x6b, 0xf2, 0x9b, 0x40, 0xeb, 0x48, + 0x37, 0x5f, 0x59, 0x61, 0xe5, 0xce, 0x42, 0x30, 0x41, 0xac, 0x9b, 0x44, 0x79, 0x70, + 0x7e, 0x42, 0x0a, 0x31, 0xe2, 0xbc, 0x6d, 0xe3, 0x5a, 0x85, 0x7c, 0x1a, 0x84, 0x5f, + 0x21, 0x76, 0xae, 0x4c, 0xd6, 0xe1, 0x9c, 0x9a, 0x0c, 0x74, 0x9e, 0x38}, + {0xce, 0xb9, 0xdc, 0x34, 0xae, 0xb3, 0xfc, 0x64, 0xad, 0xd0, 0x48, 0xe3, 0x23, 0x03, + 0x50, 0x97, 0x1b, 0x38, 0xc6, 0x62, 0x7d, 0xf0, 0xb3, 0x45, 0x88, 0x67, 0x5a, 0x46, + 0x79, 0x53, 0x54, 0x61, 0x28, 0xac, 0x0e, 0x57, 0xf6, 0x78, 0xbd, 0xc9, 0xe1, 0x9c, + 0x91, 0x27, 0x32, 0x0b, 0x5b, 0xe5, 0xed, 0x91, 0x9b, 0xa1, 0xab, 0x3e, 0xfc, 0x65, + 0x90, 0x36, 0x26, 0xd6, 0xe5, 0x25, 0xc4, 0x25, 0x6e, 0xde, 0xd7, 0xf1, 0xa6, 0x06, + 0x3e, 0x3f, 0x08, 0x23, 0x06, 0x8e, 0x27, 0x76, 0xf9, 0x3e, 0x77, 0x6c, 0x8a, 0x4e, + 0x26, 0xf6, 0x14, 0x8c, 0x59, 0x47, 0x48, 0x15, 0x89, 0xa0, 0x39, 0x65}, + {0x73, 0xf7, 0xd2, 0xc3, 0x74, 0x1f, 0xd2, 0xe9, 0x45, 0x68, 0xc4, 0x25, 0x41, 0x54, + 0x50, 0xc1, 0x33, 0x9e, 0xb9, 0xf9, 0xe8, 0x5c, 0x4e, 0x62, 0x6c, 0x18, 0xcd, 0xc5, + 0xaa, 0xe4, 0xc5, 0x11, 0x19, 0x4a, 0xbb, 0x14, 0xd4, 0xdb, 0xc4, 0xdd, 0x8e, 0x4f, + 0x42, 0x98, 0x3c, 0xbc, 0xb2, 0x19, 0x69, 0x71, 0xca, 0x36, 0xd7, 0x9f, 0xa8, 0x48, + 0x90, 0xbd, 0x19, 0xf0, 0x0e, 0x32, 0x65, 0x0f, 0xc6, 0xe0, 0xfd, 0xca, 0xb1, 0xd1, + 0x86, 0xd4, 0x81, 0x51, 0x3b, 0x16, 0xe3, 0xe6, 0x3f, 0x4f, 0x9a, 0x93, 0xf2, 0xfa, + 0x0d, 0xaf, 0xa8, 0x59, 0x2a, 0x07, 0x33, 0xec, 0xbd, 0xc7, 0xab, 0x4c}, + {0x2e, 0x0a, 0x9c, 0x08, 0x24, 0x96, 0x9e, 0x23, 0x38, 0x47, 0xfe, 0x3a, 0xc0, 0xc4, + 0x48, 0xc7, 0x2a, 0xa1, 0x4f, 0x76, 0x2a, 0xed, 0xdb, 0x17, 0x82, 0x85, 0x1c, 0x32, + 0xf0, 0x93, 0x9b, 0x63, 0x89, 0xd2, 0x78, 0x3f, 0x8f, 0x78, 0x8f, 0xc0, 0x9f, 0x4d, + 0x40, 0xa1, 0x2c, 0xa7, 0x30, 0xfe, 0x9d, 0xcc, 0x65, 0xcf, 0xfc, 0x8b, 0x77, 0xf2, + 0x21, 0x20, 0xcb, 0x5a, 0x16, 0x98, 0xe4, 0x7e, 0xc3, 0xa1, 0x11, 0x91, 0xe3, 0x08, + 0xd5, 0x7b, 0x89, 0x74, 0x90, 0x80, 0xd4, 0x90, 0x2b, 0x2b, 0x19, 0xfd, 0x72, 0xae, + 0xc2, 0xae, 0xd2, 0xe7, 0xa6, 0x02, 0xb6, 0x85, 0x3c, 0x49, 0xdf, 0x0e}, + {0x68, 0x5a, 0x9b, 0x59, 0x58, 0x81, 0xcc, 0xae, 0x0e, 0xe2, 0xad, 0xeb, 0x0f, 0x4f, + 0x57, 0xea, 0x07, 0x7f, 0xb6, 0x22, 0x74, 0x1d, 0xe4, 0x4f, 0xb4, 0x4f, 0x9d, 0x01, + 0xe3, 0x92, 0x3b, 0x40, 0x13, 0x41, 0x76, 0x84, 0xd2, 0xc4, 0x67, 0x67, 0x35, 0xf8, + 0xf5, 0xf7, 0x3f, 0x40, 0x90, 0xa0, 0xde, 0xbe, 0xe6, 0xca, 0xfa, 0xcf, 0x8f, 0x1c, + 0x69, 0xa3, 0xdf, 0xd1, 0x54, 0x0c, 0xc0, 0x04, 0xf8, 0x5c, 0x46, 0x8b, 0x81, 0x2f, + 0xc2, 0x4d, 0xf8, 0xef, 0x80, 0x14, 0x5a, 0xf3, 0xa0, 0x71, 0x57, 0xd6, 0xc7, 0x04, + 0xad, 0xbf, 0xe8, 0xae, 0xf4, 0x76, 0x61, 0xb2, 0x2a, 0xb1, 0x5b, 0x35}, + {0xf4, 0xbb, 0x93, 0x74, 0xcc, 0x64, 0x1e, 0xa7, 0xc3, 0xb0, 0xa3, 0xec, 0xd9, 0x84, + 0xbd, 0xe5, 0x85, 0xe7, 0x05, 0xfa, 0x0c, 0xc5, 0x6b, 0x0a, 0x12, 0xc3, 0x2e, 0x18, + 0x32, 0x81, 0x9b, 0x0f, 0x18, 0x73, 0x8c, 0x5a, 0xc7, 0xda, 0x01, 0xa3, 0x11, 0xaa, + 0xce, 0xb3, 0x9d, 0x03, 0x90, 0xed, 0x2d, 0x3f, 0xae, 0x3b, 0xbf, 0x7c, 0x07, 0x6f, + 0x8e, 0xad, 0x52, 0xe0, 0xf8, 0xea, 0x18, 0x75, 0x32, 0x6c, 0x7f, 0x1b, 0xc4, 0x59, + 0x88, 0xa4, 0x98, 0x32, 0x38, 0xf4, 0xbc, 0x60, 0x2d, 0x0f, 0xd9, 0xd1, 0xb1, 0xc9, + 0x29, 0xa9, 0x15, 0x18, 0xc4, 0x55, 0x17, 0xbb, 0x1b, 0x87, 0xc3, 0x47}, + {0x48, 0x4f, 0xec, 0x71, 0x97, 0x53, 0x44, 0x51, 0x6e, 0x5d, 0x8c, 0xc9, 0x7d, 0xb1, + 0x05, 0xf8, 0x6b, 0xc6, 0xc3, 0x47, 0x1a, 0xc1, 0x62, 0xf7, 0xdc, 0x99, 0x46, 0x76, + 0x85, 0x9b, 0xb8, 0x00, 0xb0, 0x66, 0x50, 0xc8, 0x50, 0x5d, 0xe6, 0xfb, 0xb0, 0x99, + 0xa2, 0xb3, 0xb0, 0xc4, 0xec, 0x62, 0xe0, 0xe8, 0x1a, 0x44, 0xea, 0x54, 0x37, 0xe5, + 0x5f, 0x8d, 0xd4, 0xe8, 0x2c, 0xa0, 0xfe, 0x08, 0xd0, 0xea, 0xde, 0x68, 0x76, 0xdd, + 0x4d, 0x82, 0x23, 0x5d, 0x68, 0x4b, 0x20, 0x45, 0x64, 0xc8, 0x65, 0xd6, 0x89, 0x5d, + 0xcd, 0xcf, 0x14, 0xb5, 0x37, 0xd5, 0x75, 0x4f, 0xa7, 0x29, 0x38, 0x47}, + {0x18, 0xc4, 0x79, 0x46, 0x75, 0xda, 0xd2, 0x82, 0xf0, 0x8d, 0x61, 0xb2, 0xd8, 0xd7, + 0x3b, 0xe6, 0x0a, 0xeb, 0x47, 0xac, 0x24, 0xef, 0x5e, 0x35, 0xb4, 0xc6, 0x33, 0x48, + 0x4c, 0x68, 0x78, 0x20, 0xc9, 0x02, 0x39, 0xad, 0x3a, 0x53, 0xd9, 0x23, 0x8f, 0x58, + 0x03, 0xef, 0xce, 0xdd, 0xc2, 0x64, 0xb4, 0x2f, 0xe1, 0xcf, 0x90, 0x73, 0x25, 0x15, + 0x90, 0xd3, 0xe4, 0x44, 0x4d, 0x8b, 0x66, 0x6c, 0x0c, 0x82, 0x78, 0x7a, 0x21, 0xcf, + 0x48, 0x3b, 0x97, 0x3e, 0x27, 0x81, 0xb2, 0x0a, 0x6a, 0xf7, 0x7b, 0xed, 0x8e, 0x8c, + 0xa7, 0x65, 0x6c, 0xa9, 0x3f, 0x43, 0x8a, 0x4f, 0x05, 0xa6, 0x11, 0x74}, + {0x6d, 0xc8, 0x9d, 0xb9, 0x32, 0x9d, 0x65, 0x4d, 0x15, 0xf1, 0x3a, 0x60, 0x75, 0xdc, + 0x4c, 0x04, 0x88, 0xe4, 0xc2, 0xdc, 0x2c, 0x71, 0x4c, 0xb3, 0xff, 0x34, 0x81, 0xfb, + 0x74, 0x65, 0x13, 0x7c, 0xb4, 0x75, 0xb1, 0x18, 0x3d, 0xe5, 0x9a, 0x57, 0x02, 0xa1, + 0x92, 0xf3, 0x59, 0x31, 0x71, 0x68, 0xf5, 0x35, 0xef, 0x1e, 0xba, 0xec, 0x55, 0x84, + 0x8f, 0x39, 0x8c, 0x45, 0x72, 0xa8, 0xc9, 0x1e, 0x9b, 0x50, 0xa2, 0x00, 0xd4, 0xa4, + 0xe6, 0xb8, 0xb4, 0x82, 0xc8, 0x0b, 0x02, 0xd7, 0x81, 0x9b, 0x61, 0x75, 0x95, 0xf1, + 0x9b, 0xcc, 0xe7, 0x57, 0x60, 0x64, 0xcd, 0xc7, 0xa5, 0x88, 0xdd, 0x3a}, + {0xf2, 0xdc, 0x35, 0xb6, 0x70, 0x57, 0x89, 0xab, 0xbc, 0x1f, 0x6c, 0xf6, 0x6c, 0xef, + 0xdf, 0x02, 0x87, 0xd1, 0xb6, 0xbe, 0x68, 0x02, 0x53, 0x85, 0x74, 0x9e, 0x87, 0xcc, + 0xfc, 0x29, 0x99, 0x24, 0x46, 0x30, 0x39, 0x59, 0xd4, 0x98, 0xc2, 0x85, 0xec, 0x59, + 0xf6, 0x5f, 0x98, 0x35, 0x7e, 0x8f, 0x3a, 0x6e, 0xf6, 0xf2, 0x2a, 0xa2, 0x2c, 0x1d, + 0x20, 0xa7, 0x06, 0xa4, 0x31, 0x11, 0xba, 0x61, 0x29, 0x90, 0x95, 0x16, 0xf1, 0xa0, + 0xd0, 0xa3, 0x89, 0xbd, 0x7e, 0xba, 0x6c, 0x6b, 0x3b, 0x02, 0x07, 0x33, 0x78, 0x26, + 0x3e, 0x5a, 0xf1, 0x7b, 0xe7, 0xec, 0xd8, 0xbb, 0x0c, 0x31, 0x20, 0x56}, + {0x43, 0xd6, 0x34, 0x49, 0x43, 0x93, 0x89, 0x52, 0xf5, 0x22, 0x12, 0xa5, 0x06, 0xf8, + 0xdb, 0xb9, 0x22, 0x1c, 0xf4, 0xc3, 0x8f, 0x87, 0x6d, 0x8f, 0x30, 0x97, 0x9d, 0x4d, + 0x2a, 0x6a, 0x67, 0x37, 0xd6, 0x85, 0xe2, 0x77, 0xf4, 0xb5, 0x46, 0x66, 0x93, 0x61, + 0x8f, 0x6c, 0x67, 0xff, 0xe8, 0x40, 0xdd, 0x94, 0xb5, 0xab, 0x11, 0x73, 0xec, 0xa6, + 0x4d, 0xec, 0x8c, 0x65, 0xf3, 0x46, 0xc8, 0x7e, 0xc7, 0x2e, 0xa2, 0x1d, 0x3f, 0x8f, + 0x5e, 0x9b, 0x13, 0xcd, 0x01, 0x6c, 0x77, 0x1d, 0x0f, 0x13, 0xb8, 0x9f, 0x98, 0xa2, + 0xcf, 0x8f, 0x4c, 0x21, 0xd5, 0x9d, 0x9b, 0x39, 0x23, 0xf7, 0xaa, 0x6d}, + {0x47, 0xbe, 0x3d, 0xeb, 0x62, 0x75, 0x3a, 0x5f, 0xb8, 0xa0, 0xbd, 0x8e, 0x54, 0x38, + 0xea, 0xf7, 0x99, 0x72, 0x74, 0x45, 0x31, 0xe5, 0xc3, 0x00, 0x51, 0xd5, 0x27, 0x16, + 0xe7, 0xe9, 0x04, 0x13, 0xa2, 0x8e, 0xad, 0xac, 0xbf, 0x04, 0x3b, 0x58, 0x84, 0xe8, + 0x8b, 0x14, 0xe8, 0x43, 0xb7, 0x29, 0xdb, 0xc5, 0x10, 0x08, 0x3b, 0x58, 0x1e, 0x2b, + 0xaa, 0xbb, 0xb3, 0x8e, 0xe5, 0x49, 0x54, 0x2b, 0xfe, 0x9c, 0xdc, 0x6a, 0xd2, 0x14, + 0x98, 0x78, 0x0b, 0xdd, 0x48, 0x8b, 0x3f, 0xab, 0x1b, 0x3c, 0x0a, 0xc6, 0x79, 0xf9, + 0xff, 0xe1, 0x0f, 0xda, 0x93, 0xd6, 0x2d, 0x7c, 0x2d, 0xde, 0x68, 0x44}, + {0x9e, 0x46, 0x19, 0x94, 0x5e, 0x35, 0xbb, 0x51, 0x54, 0xc7, 0xdd, 0x23, 0x4c, 0xdc, + 0xe6, 0x33, 0x62, 0x99, 0x7f, 0x44, 0xd6, 0xb6, 0xa5, 0x93, 0x63, 0xbd, 0x44, 0xfb, + 0x6f, 0x7c, 0xce, 0x6c, 0xce, 0x07, 0x63, 0xf8, 0xc6, 0xd8, 0x9a, 0x4b, 0x28, 0x0c, + 0x5d, 0x43, 0x31, 0x35, 0x11, 0x21, 0x2c, 0x77, 0x7a, 0x65, 0xc5, 0x66, 0xa8, 0xd4, + 0x52, 0x73, 0x24, 0x63, 0x7e, 0x42, 0xa6, 0x5d, 0xca, 0x22, 0xac, 0xde, 0x88, 0xc6, + 0x94, 0x1a, 0xf8, 0x1f, 0xae, 0xbb, 0xf7, 0x6e, 0x06, 0xb9, 0x0f, 0x58, 0x59, 0x8d, + 0x38, 0x8c, 0xad, 0x88, 0xa8, 0x2c, 0x9f, 0xe7, 0xbf, 0x9a, 0xf2, 0x58}, + {0x68, 0x3e, 0xe7, 0x8d, 0xab, 0xcf, 0x0e, 0xe9, 0xa5, 0x76, 0x7e, 0x37, 0x9f, 0x6f, + 0x03, 0x54, 0x82, 0x59, 0x01, 0xbe, 0x0b, 0x5b, 0x49, 0xf0, 0x36, 0x1e, 0xf4, 0xa7, + 0xc4, 0x29, 0x76, 0x57, 0xf6, 0xcd, 0x0e, 0x71, 0xbf, 0x64, 0x5a, 0x4b, 0x3c, 0x29, + 0x2c, 0x46, 0x38, 0xe5, 0x4c, 0xb1, 0xb9, 0x3a, 0x0b, 0xd5, 0x56, 0xd0, 0x43, 0x36, + 0x70, 0x48, 0x5b, 0x18, 0x24, 0x37, 0xf9, 0x6a, 0x88, 0xa8, 0xc6, 0x09, 0x45, 0x02, + 0x20, 0x32, 0x73, 0x89, 0x55, 0x4b, 0x13, 0x36, 0xe0, 0xd2, 0x9f, 0x28, 0x33, 0x3c, + 0x23, 0x36, 0xe2, 0x83, 0x8f, 0xc1, 0xae, 0x0c, 0xbb, 0x25, 0x1f, 0x70}, + {0xed, 0x6c, 0x61, 0xe4, 0xf8, 0xb0, 0xa8, 0xc3, 0x7d, 0xa8, 0x25, 0x9e, 0x0e, 0x66, + 0x00, 0xf7, 0x9c, 0xa5, 0xbc, 0xf4, 0x1f, 0x06, 0xe3, 0x61, 0xe9, 0x0b, 0xc4, 0xbd, + 0xbf, 0x92, 0x0c, 0x2e, 0x13, 0xc1, 0xbe, 0x7c, 0xd9, 0xf6, 0x18, 0x9d, 0xe4, 0xdb, + 0xbf, 0x74, 0xe6, 0x06, 0x4a, 0x84, 0xd6, 0x60, 0x4e, 0xac, 0x22, 0xb5, 0xf5, 0x20, + 0x51, 0x5e, 0x95, 0x50, 0xc0, 0x5b, 0x0a, 0x72, 0x35, 0x5a, 0x80, 0x9b, 0x43, 0x09, + 0x3f, 0x0c, 0xfc, 0xab, 0x42, 0x62, 0x37, 0x8b, 0x4e, 0xe8, 0x46, 0x93, 0x22, 0x5c, + 0xf3, 0x17, 0x14, 0x69, 0xec, 0xf0, 0x4e, 0x14, 0xbb, 0x9c, 0x9b, 0x0e}, + {0xad, 0x20, 0x57, 0xfb, 0x8f, 0xd4, 0xba, 0xfb, 0x0e, 0x0d, 0xf9, 0xdb, 0x6b, 0x91, + 0x81, 0xee, 0xbf, 0x43, 0x55, 0x63, 0x52, 0x31, 0x81, 0xd4, 0xd8, 0x7b, 0x33, 0x3f, + 0xeb, 0x04, 0x11, 0x22, 0xee, 0xbe, 0xb1, 0x5d, 0xd5, 0x9b, 0xee, 0x8d, 0xb9, 0x3f, + 0x72, 0x0a, 0x37, 0xab, 0xc3, 0xc9, 0x91, 0xd7, 0x68, 0x1c, 0xbf, 0xf1, 0xa8, 0x44, + 0xde, 0x3c, 0xfd, 0x1c, 0x19, 0x44, 0x6d, 0x36, 0x14, 0x8c, 0xbc, 0xf2, 0x43, 0x17, + 0x3c, 0x9e, 0x3b, 0x6c, 0x85, 0xb5, 0xfc, 0x26, 0xda, 0x2e, 0x97, 0xfb, 0xa7, 0x68, + 0x0e, 0x2f, 0xb8, 0xcc, 0x44, 0x32, 0x59, 0xbc, 0xe6, 0xa4, 0x67, 0x41}, + {0x00, 0x27, 0xf6, 0x76, 0x28, 0x9d, 0x3b, 0x64, 0xeb, 0x68, 0x76, 0x0e, 0x40, 0x9d, + 0x1d, 0x5d, 0x84, 0x06, 0xfc, 0x21, 0x03, 0x43, 0x4b, 0x1b, 0x6a, 0x24, 0x55, 0x22, + 0x7e, 0xbb, 0x38, 0x79, 0xee, 0x8f, 0xce, 0xf8, 0x65, 0x26, 0xbe, 0xc2, 0x2c, 0xd6, + 0x80, 0xe8, 0x14, 0xff, 0x67, 0xe9, 0xee, 0x4e, 0x36, 0x2f, 0x7e, 0x6e, 0x2e, 0xf1, + 0xf6, 0xd2, 0x7e, 0xcb, 0x70, 0x33, 0xb3, 0x34, 0xcc, 0xd6, 0x81, 0x86, 0xee, 0x91, + 0xc5, 0xcd, 0x53, 0xa7, 0x85, 0xed, 0x9c, 0x10, 0x02, 0xce, 0x83, 0x88, 0x80, 0x58, + 0xc1, 0x85, 0x74, 0xed, 0xe4, 0x65, 0xfe, 0x2d, 0x6e, 0xfc, 0x76, 0x11}, + {0x9b, 0x61, 0x9c, 0x5b, 0xd0, 0x6c, 0xaf, 0xb4, 0x80, 0x84, 0xa5, 0xb2, 0xf4, 0xc9, + 0xdf, 0x2d, 0xc4, 0x4d, 0xe9, 0xeb, 0x02, 0xa5, 0x4f, 0x3d, 0x34, 0x5f, 0x7d, 0x67, + 0x4c, 0x3a, 0xfc, 0x08, 0xb8, 0x0e, 0x77, 0x49, 0x89, 0xe2, 0x90, 0xdb, 0xa3, 0x40, + 0xf4, 0xac, 0x2a, 0xcc, 0xfb, 0x98, 0x9b, 0x87, 0xd7, 0xde, 0xfe, 0x4f, 0x35, 0x21, + 0xb6, 0x06, 0x69, 0xf2, 0x54, 0x3e, 0x6a, 0x1f, 0xea, 0x34, 0x07, 0xd3, 0x99, 0xc1, + 0xa4, 0x60, 0xd6, 0x5c, 0x16, 0x31, 0xb6, 0x85, 0xc0, 0x40, 0x95, 0x82, 0x59, 0xf7, + 0x23, 0x3e, 0x33, 0xe2, 0xd1, 0x00, 0xb9, 0x16, 0x01, 0xad, 0x2f, 0x4f}, + {0x54, 0x4e, 0xae, 0x94, 0x41, 0xb2, 0xbe, 0x44, 0x6c, 0xef, 0x57, 0x18, 0x51, 0x1c, + 0x54, 0x5f, 0x98, 0x04, 0x8d, 0x36, 0x2d, 0x6b, 0x1e, 0xa6, 0xab, 0xf7, 0x2e, 0x97, + 0xa4, 0x84, 0x54, 0x44, 0x38, 0xb6, 0x3b, 0xb7, 0x1d, 0xd9, 0x2c, 0x96, 0x08, 0x9c, + 0x12, 0xfc, 0xaa, 0x77, 0x05, 0xe6, 0x89, 0x16, 0xb6, 0xf3, 0x39, 0x9b, 0x61, 0x6f, + 0x81, 0xee, 0x44, 0x29, 0x5f, 0x99, 0x51, 0x34, 0x7c, 0x7d, 0xea, 0x9f, 0xd0, 0xfc, + 0x52, 0x91, 0xf6, 0x5c, 0x93, 0xb0, 0x94, 0x6c, 0x81, 0x4a, 0x40, 0x5c, 0x28, 0x47, + 0xaa, 0x9a, 0x8e, 0x25, 0xb7, 0x93, 0x28, 0x04, 0xa6, 0x9c, 0xb8, 0x10}, + {0x9c, 0x28, 0x18, 0x97, 0x49, 0x47, 0x59, 0x3d, 0x26, 0x3f, 0x53, 0x24, 0xc5, 0xf8, + 0xeb, 0x12, 0x15, 0xef, 0xc3, 0x14, 0xcb, 0xbf, 0x62, 0x02, 0x8e, 0x51, 0xb7, 0x77, + 0xd5, 0x78, 0xb8, 0x20, 0x6e, 0xf0, 0x45, 0x5a, 0xbe, 0x41, 0x39, 0x75, 0x65, 0x5f, + 0x9c, 0x6d, 0xed, 0xae, 0x7c, 0xd0, 0xb6, 0x51, 0xff, 0x72, 0x9c, 0x6b, 0x77, 0x11, + 0xa9, 0x4d, 0x0d, 0xef, 0xd9, 0xd1, 0xd2, 0x17, 0x6a, 0x3e, 0x3f, 0x07, 0x18, 0xaf, + 0xf2, 0x27, 0x69, 0x10, 0x52, 0xd7, 0x19, 0xe5, 0x3f, 0xfd, 0x22, 0x00, 0xa6, 0x3c, + 0x2c, 0xb7, 0xe3, 0x22, 0xa7, 0xc6, 0x65, 0xcc, 0x63, 0x4f, 0x21, 0x72}, + {0x93, 0xa6, 0x07, 0x53, 0x40, 0x7f, 0xe3, 0xb4, 0x95, 0x67, 0x33, 0x2f, 0xd7, 0x14, + 0xa7, 0xab, 0x99, 0x10, 0x76, 0x73, 0xa7, 0xd0, 0xfb, 0xd6, 0xc9, 0xcb, 0x71, 0x81, + 0xc5, 0x48, 0xdf, 0x5f, 0xc9, 0x29, 0x3b, 0xf4, 0xb9, 0xb7, 0x9d, 0x1d, 0x75, 0x8f, + 0x51, 0x4f, 0x4a, 0x82, 0x05, 0xd6, 0xc4, 0x9d, 0x2f, 0x31, 0xbd, 0x72, 0xc0, 0xf2, + 0xb0, 0x45, 0x15, 0x5a, 0x85, 0xac, 0x24, 0x1f, 0xaa, 0x05, 0x95, 0x8e, 0x32, 0x08, + 0xd6, 0x24, 0xee, 0x20, 0x14, 0x0c, 0xd1, 0xc1, 0x48, 0x47, 0xa2, 0x25, 0xfb, 0x06, + 0x5c, 0xe4, 0xff, 0xc7, 0xe6, 0x95, 0xe3, 0x2a, 0x9e, 0x73, 0xba, 0x00}, + {0xd6, 0x90, 0x87, 0x5c, 0xde, 0x98, 0x2e, 0x59, 0xdf, 0xa2, 0xc2, 0x45, 0xd3, 0xb7, + 0xbf, 0xe5, 0x22, 0x99, 0xb4, 0xf9, 0x60, 0x3b, 0x5a, 0x11, 0xf3, 0x78, 0xad, 0x67, + 0x3e, 0x3a, 0x28, 0x03, 0x26, 0xbb, 0x88, 0xea, 0xf5, 0x26, 0x44, 0xae, 0xfb, 0x3b, + 0x97, 0x84, 0xd9, 0x79, 0x06, 0x36, 0x50, 0x4e, 0x69, 0x26, 0x0c, 0x03, 0x9f, 0x5c, + 0x26, 0xd2, 0x18, 0xd5, 0xe7, 0x7d, 0x29, 0x72, 0x39, 0xb9, 0x0c, 0xbe, 0xc7, 0x1d, + 0x24, 0x48, 0x80, 0x30, 0x63, 0x8b, 0x4d, 0x9b, 0xf1, 0x32, 0x08, 0x93, 0x28, 0x02, + 0x0d, 0xc9, 0xdf, 0xd3, 0x45, 0x19, 0x27, 0x46, 0x68, 0x29, 0xe1, 0x05}, + {0x5a, 0x49, 0x9c, 0x2d, 0xb3, 0xee, 0x82, 0xba, 0x7c, 0xb9, 0x2b, 0xf1, 0xfc, 0xc8, + 0xef, 0xce, 0xe0, 0xd1, 0xb5, 0x93, 0xae, 0xab, 0x2d, 0xb0, 0x9b, 0x8d, 0x69, 0x13, + 0x9c, 0x0c, 0xc0, 0x39, 0x50, 0x45, 0x2c, 0x24, 0xc8, 0xbb, 0xbf, 0xad, 0xd9, 0x81, + 0x30, 0xd0, 0xec, 0x0c, 0xc8, 0xbc, 0x92, 0xdf, 0xc8, 0xf5, 0xa6, 0x66, 0x35, 0x84, + 0x4c, 0xce, 0x58, 0x82, 0xd3, 0x25, 0xcf, 0x78, 0x68, 0x9d, 0x48, 0x31, 0x8e, 0x6b, + 0xae, 0x15, 0x87, 0xf0, 0x2b, 0x9c, 0xab, 0x1c, 0x85, 0xaa, 0x05, 0xfa, 0x4e, 0xf0, + 0x97, 0x5a, 0xa7, 0xc9, 0x32, 0xf8, 0x3f, 0x6b, 0x07, 0x52, 0x6b, 0x00}, + {0x1c, 0x78, 0x95, 0x9d, 0xe1, 0xcf, 0xe0, 0x29, 0xe2, 0x10, 0x63, 0x96, 0x18, 0xdf, + 0x81, 0xb6, 0x39, 0x6b, 0x51, 0x70, 0xd3, 0x39, 0xdf, 0x57, 0x22, 0x61, 0xc7, 0x3b, + 0x44, 0xe3, 0x57, 0x4d, 0x2d, 0x08, 0xce, 0xb9, 0x16, 0x7e, 0xcb, 0xf5, 0x29, 0xbc, + 0x7a, 0x41, 0x4c, 0xf1, 0x07, 0x34, 0xab, 0xa7, 0xf4, 0x2b, 0xce, 0x6b, 0xb3, 0xd4, + 0xce, 0x75, 0x9f, 0x1a, 0x56, 0xe9, 0xe2, 0x7d, 0xcb, 0x5e, 0xa5, 0xb6, 0xf4, 0xd4, + 0x70, 0xde, 0x99, 0xdb, 0x85, 0x5d, 0x7f, 0x52, 0x01, 0x48, 0x81, 0x9a, 0xee, 0xd3, + 0x40, 0xc4, 0xc9, 0xdb, 0xed, 0x29, 0x60, 0x1a, 0xaf, 0x90, 0x2a, 0x6b}, + {0x97, 0x1e, 0xe6, 0x9a, 0xfc, 0xf4, 0x23, 0x69, 0xd1, 0x5f, 0x3f, 0xe0, 0x1d, 0x28, + 0x35, 0x57, 0x2d, 0xd1, 0xed, 0xe6, 0x43, 0xae, 0x64, 0xa7, 0x4a, 0x3e, 0x2d, 0xd1, + 0xe9, 0xf4, 0xd8, 0x5f, 0x0a, 0xd8, 0xb2, 0x5b, 0x24, 0xf3, 0xeb, 0x77, 0x9b, 0x07, + 0xb9, 0x2f, 0x47, 0x1b, 0x30, 0xd8, 0x33, 0x73, 0xee, 0x4c, 0xf2, 0xe6, 0x47, 0xc6, + 0x09, 0x21, 0x6c, 0x27, 0xc8, 0x12, 0x58, 0x46, 0xd9, 0x62, 0x10, 0x2a, 0xb2, 0xbe, + 0x43, 0x4d, 0x16, 0xdc, 0x31, 0x38, 0x75, 0xfb, 0x65, 0x70, 0xd7, 0x68, 0x29, 0xde, + 0x7b, 0x4a, 0x0d, 0x18, 0x90, 0x67, 0xb1, 0x1c, 0x2b, 0x2c, 0xb3, 0x05}, + {0xfd, 0xa8, 0x4d, 0xd2, 0xcc, 0x5e, 0xc0, 0xc8, 0x83, 0xef, 0xdf, 0x05, 0xac, 0x1a, + 0xcf, 0xa1, 0x61, 0xcd, 0xf9, 0x7d, 0xf2, 0xef, 0xbe, 0xdb, 0x99, 0x1e, 0x47, 0x7b, + 0xa3, 0x56, 0x55, 0x3b, 0x95, 0x81, 0xd5, 0x7a, 0x2c, 0xa4, 0xfc, 0xf7, 0xcc, 0xf3, + 0x33, 0x43, 0x6e, 0x28, 0x14, 0x32, 0x9d, 0x97, 0x0b, 0x34, 0x0d, 0x9d, 0xc2, 0xb6, + 0xe1, 0x07, 0x73, 0x56, 0x48, 0x1a, 0x77, 0x31, 0x82, 0xd4, 0x4d, 0xe1, 0x24, 0xc5, + 0xb0, 0x32, 0xb6, 0xa4, 0x2b, 0x1a, 0x54, 0x51, 0xb3, 0xed, 0xf3, 0x5a, 0x2b, 0x28, + 0x48, 0x60, 0xd1, 0xa3, 0xeb, 0x36, 0x73, 0x7a, 0xd2, 0x79, 0xc0, 0x4f}, + {0x7f, 0x2f, 0xbf, 0x89, 0xb0, 0x38, 0xc9, 0x51, 0xa7, 0xe9, 0xdf, 0x02, 0x65, 0xbd, + 0x97, 0x24, 0x53, 0xe4, 0x80, 0x78, 0x9c, 0xc0, 0xff, 0xff, 0x92, 0x8e, 0xf9, 0xca, + 0xce, 0x67, 0x45, 0x12, 0x0d, 0xc5, 0x86, 0x0c, 0x44, 0x8b, 0x34, 0xdc, 0x51, 0xe6, + 0x94, 0xcc, 0xc9, 0xcb, 0x37, 0x13, 0xb9, 0x3c, 0x3e, 0x64, 0x4d, 0xf7, 0x22, 0x64, + 0x08, 0xcd, 0xe3, 0xba, 0xc2, 0x70, 0x11, 0x24, 0xb4, 0x73, 0xc4, 0x0a, 0x86, 0xab, + 0xf9, 0x3f, 0x35, 0xe4, 0x13, 0x01, 0xee, 0x1d, 0x91, 0xf0, 0xaf, 0xc4, 0xc6, 0xeb, + 0x60, 0x50, 0xe7, 0x4a, 0x0d, 0x00, 0x87, 0x6c, 0x96, 0x12, 0x86, 0x3f}, + {0xde, 0x0d, 0x2a, 0x78, 0xc9, 0x0c, 0x9a, 0x55, 0x85, 0x83, 0x71, 0xea, 0xb2, 0xcd, + 0x1d, 0x55, 0x8c, 0x23, 0xef, 0x31, 0x5b, 0x86, 0x62, 0x7f, 0x3d, 0x61, 0x73, 0x79, + 0x76, 0xa7, 0x4a, 0x50, 0x13, 0x8d, 0x04, 0x36, 0xfa, 0xfc, 0x18, 0x9c, 0xdd, 0x9d, + 0x89, 0x73, 0xb3, 0x9d, 0x15, 0x29, 0xaa, 0xd0, 0x92, 0x9f, 0x0b, 0x35, 0x9f, 0xdc, + 0xd4, 0x19, 0x8a, 0x87, 0xee, 0x7e, 0xf5, 0x26, 0xb1, 0xef, 0x87, 0x56, 0xd5, 0x2c, + 0xab, 0x0c, 0x7b, 0xf1, 0x7a, 0x24, 0x62, 0xd1, 0x80, 0x51, 0x67, 0x24, 0x5a, 0x4f, + 0x34, 0x5a, 0xc1, 0x85, 0x69, 0x30, 0xba, 0x9d, 0x3d, 0x94, 0x41, 0x40}, + {0x96, 0xcc, 0xeb, 0x43, 0xba, 0xee, 0xc0, 0xc3, 0xaf, 0x9c, 0xea, 0x26, 0x9c, 0x9c, + 0x74, 0x8d, 0xc6, 0xcc, 0x77, 0x1c, 0xee, 0x95, 0xfa, 0xd9, 0x0f, 0x34, 0x84, 0x76, + 0xd9, 0xa1, 0x20, 0x14, 0xdd, 0xaa, 0x6c, 0xa2, 0x43, 0x77, 0x21, 0x4b, 0xce, 0xb7, + 0x8a, 0x64, 0x24, 0xb4, 0xa6, 0x47, 0xe3, 0xc9, 0xfb, 0x03, 0x7a, 0x4f, 0x1d, 0xcb, + 0x19, 0xd0, 0x00, 0x98, 0x42, 0x31, 0xd9, 0x12, 0x4f, 0x59, 0x37, 0xd3, 0x99, 0x77, + 0xc6, 0x00, 0x7b, 0xa4, 0x3a, 0xb2, 0x40, 0x51, 0x3c, 0x5e, 0x95, 0xf3, 0x5f, 0xe3, + 0x54, 0x28, 0x18, 0x44, 0x12, 0xa0, 0x59, 0x43, 0x31, 0x92, 0x4f, 0x1b}, + {0x51, 0x09, 0x15, 0x89, 0x9d, 0x10, 0x5c, 0x3e, 0x6a, 0x69, 0xe9, 0x2d, 0x91, 0xfa, + 0xce, 0x39, 0x20, 0x30, 0x5f, 0x97, 0x3f, 0xe4, 0xea, 0x20, 0xae, 0x2d, 0x13, 0x7f, + 0x2a, 0x57, 0x9b, 0x23, 0xb1, 0x66, 0x98, 0xa4, 0x30, 0x30, 0xcf, 0x33, 0x59, 0x48, + 0x5f, 0x21, 0xd2, 0x73, 0x1f, 0x25, 0xf6, 0xf4, 0xde, 0x51, 0x40, 0xaa, 0x82, 0xab, + 0xf6, 0x23, 0x9a, 0x6f, 0xd5, 0x91, 0xf1, 0x5f, 0x68, 0x90, 0x2d, 0xac, 0x33, 0xd4, + 0x9e, 0x81, 0x23, 0x85, 0xc9, 0x5f, 0x79, 0xab, 0x83, 0x28, 0x3d, 0xeb, 0x93, 0x55, + 0x80, 0x72, 0x45, 0xef, 0xcb, 0x36, 0x8f, 0x75, 0x6a, 0x52, 0x0c, 0x02}, + {0xbc, 0xdb, 0xd8, 0x9e, 0xf8, 0x34, 0x98, 0x77, 0x6c, 0xa4, 0x7c, 0xdc, 0xf9, 0xaa, + 0xf2, 0xc8, 0x74, 0xb0, 0xe1, 0xa3, 0xdc, 0x4c, 0x52, 0xa9, 0x77, 0x38, 0x31, 0x15, + 0x46, 0xcc, 0xaa, 0x02, 0x89, 0xcc, 0x42, 0xf0, 0x59, 0xef, 0x31, 0xe9, 0xb6, 0x4b, + 0x12, 0x8e, 0x9d, 0x9c, 0x58, 0x2c, 0x97, 0x59, 0xc7, 0xae, 0x8a, 0xe1, 0xc8, 0xad, + 0x0c, 0xc5, 0x02, 0x56, 0x0a, 0xfe, 0x2c, 0x45, 0xdf, 0x77, 0x78, 0x64, 0xa0, 0xf7, + 0xa0, 0x86, 0x9f, 0x7c, 0x60, 0x0e, 0x27, 0x64, 0xc4, 0xbb, 0xc9, 0x11, 0xfb, 0xf1, + 0x25, 0xea, 0x17, 0xab, 0x7b, 0x87, 0x4b, 0x30, 0x7b, 0x7d, 0xfb, 0x4c}, + {0xfe, 0x75, 0x9b, 0xb8, 0x6c, 0x3d, 0xb4, 0x72, 0x80, 0xdc, 0x6a, 0x9c, 0xd9, 0x94, + 0xc6, 0x54, 0x9f, 0x4c, 0xe3, 0x3e, 0x37, 0xaa, 0xc3, 0xb8, 0x64, 0x53, 0x07, 0x39, + 0x2b, 0x62, 0xb4, 0x14, 0x12, 0xef, 0x89, 0x97, 0xc2, 0x99, 0x86, 0xe2, 0x0d, 0x19, + 0x57, 0xdf, 0x71, 0xcd, 0x6e, 0x2b, 0xd0, 0x70, 0xc9, 0xec, 0x57, 0xc8, 0x43, 0xc3, + 0xc5, 0x3a, 0x4d, 0x43, 0xbc, 0x4c, 0x1d, 0x5b, 0x26, 0x9f, 0x0a, 0xcc, 0x15, 0x26, + 0xfb, 0xb6, 0xe5, 0xcc, 0x8d, 0xb8, 0x2b, 0x0e, 0x4f, 0x3a, 0x05, 0xa7, 0x69, 0x33, + 0x8b, 0x49, 0x01, 0x13, 0xd1, 0x2d, 0x59, 0x58, 0x12, 0xf7, 0x98, 0x2f}, + {0x56, 0x9e, 0x0f, 0xb5, 0x4c, 0xa7, 0x94, 0x0c, 0x20, 0x13, 0x8e, 0x8e, 0xa9, 0xf4, + 0x1f, 0x5b, 0x67, 0x0f, 0x30, 0x82, 0x21, 0xcc, 0x2a, 0x9a, 0xf9, 0xaa, 0x06, 0xd8, + 0x49, 0xe2, 0x6a, 0x3a, 0x01, 0xa7, 0x54, 0x4f, 0x44, 0xae, 0x12, 0x2e, 0xde, 0xd7, + 0xcb, 0xa9, 0xf0, 0x3e, 0xfe, 0xfc, 0xe0, 0x5d, 0x83, 0x75, 0x0d, 0x89, 0xbf, 0xce, + 0x54, 0x45, 0x61, 0xe7, 0xe9, 0x62, 0x80, 0x1d, 0x5a, 0x7c, 0x90, 0xa9, 0x85, 0xda, + 0x7a, 0x65, 0x62, 0x0f, 0xb9, 0x91, 0xb5, 0xa8, 0x0e, 0x1a, 0xe9, 0xb4, 0x34, 0xdf, + 0xfb, 0x1d, 0x0e, 0x8d, 0xf3, 0x5f, 0xf2, 0xae, 0xe8, 0x8c, 0x8b, 0x29}, + {0xb2, 0x0c, 0xf7, 0xef, 0x53, 0x79, 0x92, 0x2a, 0x76, 0x70, 0x15, 0x79, 0x2a, 0xc9, + 0x89, 0x4b, 0x6a, 0xcf, 0xa7, 0x30, 0x7a, 0x45, 0x18, 0x94, 0x85, 0xe4, 0x5c, 0x4d, + 0x40, 0xa8, 0xb8, 0x34, 0xde, 0x65, 0x21, 0x0a, 0xea, 0x72, 0x7a, 0x83, 0xf6, 0x79, + 0xcf, 0x0b, 0xb4, 0x07, 0xab, 0x3f, 0x70, 0xae, 0x38, 0x77, 0xc7, 0x36, 0x16, 0x52, + 0xdc, 0xd7, 0xa7, 0x03, 0x18, 0x27, 0xa6, 0x6b, 0x35, 0x33, 0x69, 0x83, 0xb5, 0xec, + 0x6e, 0xc2, 0xfd, 0xfe, 0xb5, 0x63, 0xdf, 0x13, 0xa8, 0xd5, 0x73, 0x25, 0xb2, 0xa4, + 0x9a, 0xaa, 0x93, 0xa2, 0x6a, 0x1c, 0x5e, 0x46, 0xdd, 0x2b, 0xd6, 0x71}, + {0x80, 0xdf, 0x78, 0xd3, 0x28, 0xcc, 0x33, 0x65, 0xb4, 0xa4, 0x0f, 0x0a, 0x79, 0x43, + 0xdb, 0xf6, 0x5a, 0xda, 0x01, 0xf7, 0xf9, 0x5f, 0x64, 0xe3, 0xa4, 0x2b, 0x17, 0xf3, + 0x17, 0xf3, 0xd5, 0x74, 0xf5, 0x5e, 0xf7, 0xb1, 0xda, 0xb5, 0x2d, 0xcd, 0xf5, 0x65, + 0xb0, 0x16, 0xcf, 0x95, 0x7f, 0xd7, 0x85, 0xf0, 0x49, 0x3f, 0xea, 0x1f, 0x57, 0x14, + 0x3d, 0x2b, 0x2b, 0x26, 0x21, 0x36, 0x33, 0x1c, 0x81, 0xca, 0xd9, 0x67, 0x54, 0xe5, + 0x6f, 0xa8, 0x37, 0x8c, 0x29, 0x2b, 0x75, 0x7c, 0x8b, 0x39, 0x3b, 0x62, 0xac, 0xe3, + 0x92, 0x08, 0x6d, 0xda, 0x8c, 0xd9, 0xe9, 0x47, 0x45, 0xcc, 0xeb, 0x4a}, + {0xc9, 0x01, 0x6d, 0x27, 0x1b, 0x07, 0xf0, 0x12, 0x70, 0x8c, 0xc4, 0x86, 0xc5, 0xba, + 0xb8, 0xe7, 0xa9, 0xfb, 0xd6, 0x71, 0x9b, 0x12, 0x08, 0x53, 0x92, 0xb7, 0x3d, 0x5a, + 0xf9, 0xfb, 0x88, 0x5d, 0x10, 0xb6, 0x54, 0x73, 0x9e, 0x8d, 0x40, 0x0b, 0x6e, 0x5b, + 0xa8, 0x5b, 0x53, 0x32, 0x6b, 0x80, 0x07, 0xa2, 0x58, 0x4a, 0x03, 0x3a, 0xe6, 0xdb, + 0x2c, 0xdf, 0xa1, 0xc9, 0xdd, 0xd9, 0x3b, 0x17, 0xdf, 0x72, 0x58, 0xfe, 0x1e, 0x0f, + 0x50, 0x2b, 0xc1, 0x18, 0x39, 0xd4, 0x2e, 0x58, 0xd6, 0x58, 0xe0, 0x3a, 0x67, 0xc9, + 0x8e, 0x27, 0xed, 0xe6, 0x19, 0xa3, 0x9e, 0xb1, 0x13, 0xcd, 0xe1, 0x06}, + {0x23, 0x6f, 0x16, 0x6f, 0x51, 0xad, 0xd0, 0x40, 0xbe, 0x6a, 0xab, 0x1f, 0x93, 0x32, + 0x8e, 0x11, 0x8e, 0x08, 0x4d, 0xa0, 0x14, 0x5e, 0xe3, 0x3f, 0x66, 0x62, 0xe1, 0x26, + 0x35, 0x60, 0x80, 0x30, 0x53, 0x03, 0x5b, 0x9e, 0x62, 0xaf, 0x2b, 0x47, 0x47, 0x04, + 0x8d, 0x27, 0x90, 0x0b, 0xaa, 0x3b, 0x27, 0xbf, 0x43, 0x96, 0x46, 0x5f, 0x78, 0x0c, + 0x13, 0x7b, 0x83, 0x8d, 0x1a, 0x6a, 0x3a, 0x7f, 0x0b, 0x80, 0x3d, 0x5d, 0x39, 0x44, + 0xe6, 0xf7, 0xf6, 0xed, 0x01, 0xc9, 0x55, 0xd5, 0xa8, 0x95, 0x39, 0x63, 0x2c, 0x59, + 0x30, 0x78, 0xcd, 0x68, 0x7e, 0x30, 0x51, 0x2e, 0xed, 0xfd, 0xd0, 0x30}, + {0xb3, 0x33, 0x12, 0xf2, 0x1a, 0x4d, 0x59, 0xe0, 0x9c, 0x4d, 0xcc, 0xf0, 0x8e, 0xe7, + 0xdb, 0x1b, 0x77, 0x9a, 0x49, 0x8f, 0x7f, 0x18, 0x65, 0x69, 0x68, 0x98, 0x09, 0x2c, + 0x20, 0x14, 0x92, 0x0a, 0x50, 0x47, 0xb8, 0x68, 0x1e, 0x97, 0xb4, 0x9c, 0xcf, 0xbb, + 0x64, 0x66, 0x29, 0x72, 0x95, 0xa0, 0x2b, 0x41, 0xfa, 0x72, 0x26, 0xe7, 0x8d, 0x5c, + 0xd9, 0x89, 0xc5, 0x51, 0x43, 0x08, 0x15, 0x46, 0x2e, 0xa0, 0xb9, 0xae, 0xc0, 0x19, + 0x90, 0xbc, 0xae, 0x4c, 0x03, 0x16, 0x0d, 0x11, 0xc7, 0x55, 0xec, 0x32, 0x99, 0x65, + 0x01, 0xf5, 0x6d, 0x0e, 0xfe, 0x5d, 0xca, 0x95, 0x28, 0x0d, 0xca, 0x3b}, + {0xa4, 0x62, 0x5d, 0x3c, 0xbc, 0x31, 0xf0, 0x40, 0x60, 0x7a, 0xf0, 0xcf, 0x3e, 0x8b, + 0xfc, 0x19, 0x45, 0xb5, 0x0f, 0x13, 0xa2, 0x3d, 0x18, 0x98, 0xcd, 0x13, 0x8f, 0xae, + 0xdd, 0xde, 0x31, 0x56, 0xbf, 0x01, 0xcc, 0x9e, 0xb6, 0x8e, 0x68, 0x9c, 0x6f, 0x89, + 0x44, 0xa6, 0xad, 0x83, 0xbc, 0xf0, 0xe2, 0x9f, 0x7a, 0x5f, 0x5f, 0x95, 0x2d, 0xca, + 0x41, 0x82, 0xf2, 0x8d, 0x03, 0xb4, 0xa8, 0x4e, 0x02, 0xd2, 0xca, 0xf1, 0x0a, 0x46, + 0xed, 0x2a, 0x83, 0xee, 0x8c, 0xa4, 0x05, 0x53, 0x30, 0x46, 0x5f, 0x1a, 0xf1, 0x49, + 0x45, 0x77, 0x21, 0x91, 0x63, 0xa4, 0x2c, 0x54, 0x30, 0x09, 0xce, 0x24}, + {0x06, 0xc1, 0x06, 0xfd, 0xf5, 0x90, 0xe8, 0x1f, 0xf2, 0x10, 0x88, 0x5d, 0x35, 0x68, + 0xc4, 0xb5, 0x3e, 0xaf, 0x8c, 0x6e, 0xfe, 0x08, 0x78, 0x82, 0x4b, 0xd7, 0x06, 0x8a, + 0xc2, 0xe3, 0xd4, 0x41, 0x85, 0x0b, 0xf3, 0xfd, 0x55, 0xa1, 0xcf, 0x3f, 0xa4, 0x2e, + 0x37, 0x36, 0x8e, 0x16, 0xf7, 0xd2, 0x44, 0xf8, 0x92, 0x64, 0xde, 0x64, 0xe0, 0xb2, + 0x80, 0x42, 0x4f, 0x32, 0xa7, 0x28, 0x99, 0x54, 0x2e, 0x1a, 0xee, 0x63, 0xa7, 0x32, + 0x6e, 0xf2, 0xea, 0xfd, 0x5f, 0xd2, 0xb7, 0xe4, 0x91, 0xae, 0x69, 0x4d, 0x7f, 0xd1, + 0x3b, 0xd3, 0x3b, 0xbc, 0x6a, 0xff, 0xdc, 0xc0, 0xde, 0x66, 0x1b, 0x49}, + {0xa7, 0x32, 0xea, 0xc7, 0x3d, 0xb1, 0xf5, 0x98, 0x98, 0xdb, 0x16, 0x7e, 0xcc, 0xf8, + 0xd5, 0xe3, 0x47, 0xd9, 0xf8, 0xcb, 0x52, 0xbf, 0x0a, 0xac, 0xac, 0xe4, 0x5e, 0xc8, + 0xd0, 0x38, 0xf3, 0x08, 0xa1, 0x64, 0xda, 0xd0, 0x8e, 0x4a, 0xf0, 0x75, 0x4b, 0x28, + 0xe2, 0x67, 0xaf, 0x2c, 0x22, 0xed, 0xa4, 0x7b, 0x7b, 0x1f, 0x79, 0xa3, 0x34, 0x82, + 0x67, 0x8b, 0x01, 0xb7, 0xb0, 0xb8, 0xf6, 0x4c, 0xbd, 0x73, 0x1a, 0x99, 0x21, 0xa8, + 0x83, 0xc3, 0x7a, 0x0c, 0x32, 0xdf, 0x01, 0xbc, 0x27, 0xab, 0x63, 0x70, 0x77, 0x84, + 0x1b, 0x33, 0x3d, 0xc1, 0x99, 0x8a, 0x07, 0xeb, 0x82, 0x4a, 0x0d, 0x53}, + {0x25, 0x48, 0xf9, 0xe1, 0x30, 0x36, 0x4c, 0x00, 0x5a, 0x53, 0xab, 0x8c, 0x26, 0x78, + 0x2d, 0x7e, 0x8b, 0xff, 0x84, 0xcc, 0x23, 0x23, 0x48, 0xc7, 0xb9, 0x70, 0x17, 0x10, + 0x3f, 0x75, 0xea, 0x65, 0x9e, 0xbf, 0x9a, 0x6c, 0x45, 0x73, 0x69, 0x6d, 0x80, 0xa8, + 0x00, 0x49, 0xfc, 0xb2, 0x7f, 0x25, 0x50, 0xb8, 0xcf, 0xc8, 0x12, 0xf4, 0xac, 0x2b, + 0x5b, 0xbd, 0xbf, 0x0c, 0xe0, 0xe7, 0xb3, 0x0d, 0x63, 0x63, 0x09, 0xe2, 0x3e, 0xfc, + 0x66, 0x3d, 0x6b, 0xcb, 0xb5, 0x61, 0x7f, 0x2c, 0xd6, 0x81, 0x1a, 0x3b, 0x44, 0x13, + 0x42, 0x04, 0xbe, 0x0f, 0xdb, 0xa1, 0xe1, 0x21, 0x19, 0xec, 0xa4, 0x02}, + {0xa2, 0xb8, 0x24, 0x3b, 0x9a, 0x25, 0xe6, 0x5c, 0xb8, 0xa0, 0xaf, 0x45, 0xcc, 0x7a, + 0x57, 0xb8, 0x37, 0x70, 0xa0, 0x8b, 0xe8, 0xe6, 0xcb, 0xcc, 0xbf, 0x09, 0x78, 0x12, + 0x51, 0x3c, 0x14, 0x3d, 0x5f, 0x79, 0xcf, 0xf1, 0x62, 0x61, 0xc8, 0xf5, 0xf2, 0x57, + 0xee, 0x26, 0x19, 0x86, 0x8c, 0x11, 0x78, 0x35, 0x06, 0x1c, 0x85, 0x24, 0x21, 0x17, + 0xcf, 0x7f, 0x06, 0xec, 0x5d, 0x2b, 0xd1, 0x36, 0x57, 0x45, 0x15, 0x79, 0x91, 0x27, + 0x6d, 0x12, 0x0a, 0x3a, 0x78, 0xfc, 0x5c, 0x8f, 0xe4, 0xd5, 0xac, 0x9b, 0x17, 0xdf, + 0xe8, 0xb6, 0xbd, 0x36, 0x59, 0x28, 0xa8, 0x5b, 0x88, 0x17, 0xf5, 0x2e}, + {0xdc, 0xae, 0x58, 0x8c, 0x4e, 0x97, 0x37, 0x46, 0xa4, 0x41, 0xf0, 0xab, 0xfb, 0x22, + 0xef, 0xb9, 0x8a, 0x71, 0x80, 0xe9, 0x56, 0xd9, 0x85, 0xe1, 0xa6, 0xa8, 0x43, 0xb1, + 0xfa, 0x78, 0x1b, 0x2f, 0x51, 0x2f, 0x5b, 0x30, 0xfb, 0xbf, 0xee, 0x96, 0xb8, 0x96, + 0x95, 0x88, 0xad, 0x38, 0xf9, 0xd3, 0x25, 0xdd, 0xd5, 0x46, 0xc7, 0x2d, 0xf5, 0xf0, + 0x95, 0x00, 0x3a, 0xbb, 0x90, 0x82, 0x96, 0x57, 0x01, 0xe1, 0x20, 0x0a, 0x43, 0xb8, + 0x1a, 0xf7, 0x47, 0xec, 0xf0, 0x24, 0x8d, 0x65, 0x93, 0xf3, 0xd1, 0xee, 0xe2, 0x6e, + 0xa8, 0x09, 0x75, 0xcf, 0xe1, 0xa3, 0x2a, 0xdc, 0x35, 0x3e, 0xc4, 0x7d}, + {0xc3, 0xd9, 0x7d, 0x88, 0x65, 0x66, 0x96, 0x85, 0x55, 0x53, 0xb0, 0x4b, 0x31, 0x9b, + 0x0f, 0xc9, 0xb1, 0x79, 0x20, 0xef, 0xf8, 0x8d, 0xe0, 0xc6, 0x2f, 0xc1, 0x8c, 0x75, + 0x16, 0x20, 0xf7, 0x7e, 0x18, 0x97, 0x3e, 0x27, 0x5c, 0x2a, 0x78, 0x5a, 0x94, 0xfd, + 0x4e, 0x5e, 0x99, 0xc6, 0x76, 0x35, 0x3e, 0x7d, 0x23, 0x1f, 0x05, 0xd8, 0x2e, 0x0f, + 0x99, 0x0a, 0xd5, 0x82, 0x1d, 0xb8, 0x4f, 0x04, 0xd9, 0xe3, 0x07, 0xa9, 0xc5, 0x18, + 0xdf, 0xc1, 0x59, 0x63, 0x4c, 0xce, 0x1d, 0x37, 0xb3, 0x57, 0x49, 0xbb, 0x01, 0xb2, + 0x34, 0x45, 0x70, 0xca, 0x2e, 0xdd, 0x30, 0x9c, 0x3f, 0x82, 0x79, 0x7f}, + {0xe8, 0x13, 0xb5, 0xa3, 0x39, 0xd2, 0x34, 0x83, 0xd8, 0xa8, 0x1f, 0xb9, 0xd4, 0x70, + 0x36, 0xc1, 0x33, 0xbd, 0x90, 0xf5, 0x36, 0x41, 0xb5, 0x12, 0xb4, 0xd9, 0x84, 0xd7, + 0x73, 0x03, 0x4e, 0x0a, 0xba, 0x87, 0xf5, 0x68, 0xf0, 0x1f, 0x9c, 0x6a, 0xde, 0xc8, + 0x50, 0x00, 0x4e, 0x89, 0x27, 0x08, 0xe7, 0x5b, 0xed, 0x7d, 0x55, 0x99, 0xbf, 0x3c, + 0xf0, 0xd6, 0x06, 0x1c, 0x43, 0xb0, 0xa9, 0x64, 0x19, 0x29, 0x7d, 0x5b, 0xa1, 0xd6, + 0xb3, 0x2e, 0x35, 0x82, 0x3a, 0xd5, 0xa0, 0xf6, 0xb4, 0xb0, 0x47, 0x5d, 0xa4, 0x89, + 0x43, 0xce, 0x56, 0x71, 0x6c, 0x34, 0x18, 0xce, 0x0a, 0x7d, 0x1a, 0x07}, + {0x0b, 0xba, 0x87, 0xc8, 0xaa, 0x2d, 0x07, 0xd3, 0xee, 0x62, 0xa5, 0xbf, 0x05, 0x29, + 0x26, 0x01, 0x8b, 0x76, 0xef, 0xc0, 0x02, 0x30, 0x54, 0xcf, 0x9c, 0x7e, 0xea, 0x46, + 0x71, 0xcc, 0x3b, 0x2c, 0x31, 0x44, 0xe1, 0x20, 0x52, 0x35, 0x0c, 0xcc, 0x41, 0x51, + 0xb1, 0x09, 0x07, 0x95, 0x65, 0x0d, 0x36, 0x5f, 0x9d, 0x20, 0x1b, 0x62, 0xf5, 0x9a, + 0xd3, 0x55, 0x77, 0x61, 0xf7, 0xbc, 0x69, 0x7c, 0x5f, 0x29, 0xe8, 0x04, 0xeb, 0xd7, + 0xf0, 0x07, 0x7d, 0xf3, 0x50, 0x2f, 0x25, 0x18, 0xdb, 0x10, 0xd7, 0x98, 0x17, 0x17, + 0xa3, 0xa9, 0x51, 0xe9, 0x1d, 0xa5, 0xac, 0x22, 0x73, 0x9a, 0x5a, 0x6f}, + {0xc5, 0xc6, 0x41, 0x2f, 0x0c, 0x00, 0xa1, 0x8b, 0x9b, 0xfb, 0xfe, 0x0c, 0xc1, 0x79, + 0x9f, 0xc4, 0x9f, 0x1c, 0xc5, 0x3c, 0x70, 0x47, 0xfa, 0x4e, 0xca, 0xaf, 0x47, 0xe1, + 0xa2, 0x21, 0x4e, 0x49, 0xbe, 0x44, 0xd9, 0xa3, 0xeb, 0xd4, 0x29, 0xe7, 0x9e, 0xaf, + 0x78, 0x80, 0x40, 0x09, 0x9e, 0x8d, 0x03, 0x9c, 0x86, 0x47, 0x7a, 0x56, 0x25, 0x45, + 0x24, 0x3b, 0x8d, 0xee, 0x80, 0x96, 0xab, 0x02, 0x9a, 0x0d, 0xe5, 0xdd, 0x85, 0x8a, + 0xa4, 0xef, 0x49, 0xa2, 0xb9, 0x0f, 0x4e, 0x22, 0x9a, 0x21, 0xd9, 0xf6, 0x1e, 0xd9, + 0x1d, 0x1f, 0x09, 0xfa, 0x34, 0xbb, 0x46, 0xea, 0xcb, 0x76, 0x5d, 0x6b}, + {0x94, 0xd9, 0x0c, 0xec, 0x6c, 0x55, 0x57, 0x88, 0xba, 0x1d, 0xd0, 0x5c, 0x6f, 0xdc, + 0x72, 0x64, 0x77, 0xb4, 0x42, 0x8f, 0x14, 0x69, 0x01, 0xaf, 0x54, 0x73, 0x27, 0x85, + 0xf6, 0x33, 0xe3, 0x0a, 0x22, 0x25, 0x78, 0x1e, 0x17, 0x41, 0xf9, 0xe0, 0xd3, 0x36, + 0x69, 0x03, 0x74, 0xae, 0xe6, 0xf1, 0x46, 0xc7, 0xfc, 0xd0, 0xa2, 0x3e, 0x8b, 0x40, + 0x3e, 0x31, 0xdd, 0x03, 0x9c, 0x86, 0xfb, 0x16, 0x62, 0x09, 0xb6, 0x33, 0x97, 0x19, + 0x8e, 0x28, 0x33, 0xe1, 0xab, 0xd8, 0xb4, 0x72, 0xfc, 0x24, 0x3e, 0xd0, 0x91, 0x09, + 0xed, 0xf7, 0x11, 0x48, 0x75, 0xd0, 0x70, 0x8f, 0x8b, 0xe3, 0x81, 0x3f}, + {0xfe, 0xaf, 0xd9, 0x7e, 0xcc, 0x0f, 0x91, 0x7f, 0x4b, 0x87, 0x65, 0x24, 0xa1, 0xb8, + 0x5c, 0x54, 0x04, 0x47, 0x0c, 0x4b, 0xd2, 0x7e, 0x39, 0xa8, 0x93, 0x09, 0xf5, 0x04, + 0xc1, 0x0f, 0x51, 0x50, 0x24, 0xc8, 0x17, 0x5f, 0x35, 0x7f, 0xdb, 0x0a, 0xa4, 0x99, + 0x42, 0xd7, 0xc3, 0x23, 0xb9, 0x74, 0xf7, 0xea, 0xf8, 0xcb, 0x8b, 0x3e, 0x7c, 0xd5, + 0x3d, 0xdc, 0xde, 0x4c, 0xd3, 0xe2, 0xd3, 0x0a, 0x9d, 0x24, 0x6e, 0x33, 0xc5, 0x0f, + 0x0c, 0x6f, 0xd9, 0xcf, 0x31, 0xc3, 0x19, 0xde, 0x5e, 0x74, 0x1c, 0xfe, 0xee, 0x09, + 0x00, 0xfd, 0xd6, 0xf2, 0xbe, 0x1e, 0xfa, 0xf0, 0x8b, 0x15, 0x7c, 0x12}, + {0xa2, 0x79, 0x98, 0x2e, 0x42, 0x7c, 0x19, 0xf6, 0x47, 0x36, 0xca, 0x52, 0xd4, 0xdd, + 0x4a, 0xa4, 0xcb, 0xac, 0x4e, 0x4b, 0xc1, 0x3f, 0x41, 0x9b, 0x68, 0x4f, 0xef, 0x07, + 0x7d, 0xf8, 0x4e, 0x35, 0x74, 0xb9, 0x51, 0xae, 0xc4, 0x8f, 0xa2, 0xde, 0x96, 0xfe, + 0x4d, 0x74, 0xd3, 0x73, 0x99, 0x1d, 0xa8, 0x48, 0x38, 0x87, 0x0b, 0x68, 0x40, 0x62, + 0x95, 0xdf, 0x67, 0xd1, 0x79, 0x24, 0xd8, 0x4e, 0x75, 0xd9, 0xc5, 0x60, 0x22, 0xb5, + 0xe3, 0xfe, 0xb8, 0xb0, 0x41, 0xeb, 0xfc, 0x2e, 0x35, 0x50, 0x3c, 0x65, 0xf6, 0xa9, + 0x30, 0xac, 0x08, 0x88, 0x6d, 0x23, 0x39, 0x05, 0xd2, 0x92, 0x2d, 0x30}, + {0x3d, 0x28, 0xa4, 0xbc, 0xa2, 0xc1, 0x13, 0x78, 0xd9, 0x3d, 0x86, 0xa1, 0x91, 0xf0, + 0x62, 0xed, 0x86, 0xfa, 0x68, 0xc2, 0xb8, 0xbc, 0xc7, 0xae, 0x4c, 0xae, 0x1c, 0x6f, + 0xb7, 0xd3, 0xe5, 0x10, 0x77, 0xf1, 0xe0, 0xe4, 0xb6, 0x6f, 0xbc, 0x2d, 0x93, 0x6a, + 0xbd, 0xa4, 0x29, 0xbf, 0xe1, 0x04, 0xe8, 0xf6, 0x7a, 0x78, 0xd4, 0x66, 0x19, 0x5e, + 0x60, 0xd0, 0x26, 0xb4, 0x5e, 0x5f, 0xdc, 0x0e, 0x67, 0x8e, 0xda, 0x53, 0xd6, 0xbf, + 0x53, 0x54, 0x41, 0xf6, 0xa9, 0x24, 0xec, 0x1e, 0xdc, 0xe9, 0x23, 0x8a, 0x57, 0x03, + 0x3b, 0x26, 0x87, 0xbf, 0x72, 0xba, 0x1c, 0x36, 0x51, 0x6c, 0xb4, 0x45}, + {0xa1, 0x7f, 0x4f, 0x31, 0xbf, 0x2a, 0x40, 0xa9, 0x50, 0xf4, 0x8c, 0x8e, 0xdc, 0xf1, + 0x57, 0xe2, 0x84, 0xbe, 0xa8, 0x23, 0x4b, 0xd5, 0xbb, 0x1d, 0x3b, 0x71, 0xcb, 0x6d, + 0xa3, 0xbf, 0x77, 0x21, 0xe4, 0xe3, 0x7f, 0x8a, 0xdd, 0x4d, 0x9d, 0xce, 0x30, 0x0e, + 0x62, 0x76, 0x56, 0x64, 0x13, 0xab, 0x58, 0x99, 0x0e, 0xb3, 0x7b, 0x4f, 0x59, 0x4b, + 0xdf, 0x29, 0x12, 0x32, 0xef, 0x0a, 0x1c, 0x5c, 0x8f, 0xdb, 0x79, 0xfa, 0xbc, 0x1b, + 0x08, 0x37, 0xb3, 0x59, 0x5f, 0xc2, 0x1e, 0x81, 0x48, 0x60, 0x87, 0x24, 0x83, 0x9c, + 0x65, 0x76, 0x7a, 0x08, 0xbb, 0xb5, 0x8a, 0x7d, 0x38, 0x19, 0xe6, 0x4a}, + {0x2e, 0xa3, 0x44, 0x53, 0xaa, 0xf6, 0xdb, 0x8d, 0x78, 0x40, 0x1b, 0xb4, 0xb4, 0xea, + 0x88, 0x7d, 0x60, 0x0d, 0x13, 0x4a, 0x97, 0xeb, 0xb0, 0x5e, 0x03, 0x3e, 0xbf, 0x17, + 0x1b, 0xd9, 0x00, 0x1a, 0x83, 0xfb, 0x5b, 0x98, 0x44, 0x7e, 0x11, 0x61, 0x36, 0x31, + 0x96, 0x71, 0x2a, 0x46, 0xe0, 0xfc, 0x4b, 0x90, 0x25, 0xd4, 0x48, 0x34, 0xac, 0x83, + 0x64, 0x3d, 0xa4, 0x5b, 0xbe, 0x5a, 0x68, 0x75, 0xb2, 0xf2, 0x61, 0xeb, 0x33, 0x09, + 0x96, 0x6e, 0x52, 0x49, 0xff, 0xc9, 0xa8, 0x0f, 0x3d, 0x54, 0x69, 0x65, 0xf6, 0x7a, + 0x10, 0x75, 0x72, 0xdf, 0xaa, 0xe6, 0xb0, 0x23, 0xb6, 0x29, 0x55, 0x13}, + {0x18, 0xd5, 0xd1, 0xad, 0xd7, 0xdb, 0xf0, 0x18, 0x11, 0x1f, 0xc1, 0xcf, 0x88, 0x78, + 0x9f, 0x97, 0x9b, 0x75, 0x14, 0x71, 0xf0, 0xe1, 0x32, 0x87, 0x01, 0x3a, 0xca, 0x65, + 0x1a, 0xb8, 0xb5, 0x79, 0xfe, 0x83, 0x2e, 0xe2, 0xbc, 0x16, 0xc7, 0xf5, 0xc1, 0x85, + 0x09, 0xe8, 0x19, 0xeb, 0x2b, 0xb4, 0xae, 0x4a, 0x25, 0x14, 0x37, 0xa6, 0x9d, 0xec, + 0x13, 0xa6, 0x90, 0x15, 0x05, 0xea, 0x72, 0x59, 0x11, 0x78, 0x8f, 0xdc, 0x20, 0xac, + 0xd4, 0x0f, 0xa8, 0x4f, 0x4d, 0xac, 0x94, 0xd2, 0x9a, 0x9a, 0x34, 0x04, 0x36, 0xb3, + 0x64, 0x2d, 0x1b, 0xc0, 0xdb, 0x3b, 0x5f, 0x90, 0x95, 0x9c, 0x7e, 0x4f}, + {0x2e, 0x30, 0x81, 0x57, 0xbc, 0x4b, 0x67, 0x62, 0x0f, 0xdc, 0xad, 0x89, 0x39, 0x0f, + 0x52, 0xd8, 0xc6, 0xd9, 0xfb, 0x53, 0xae, 0x99, 0x29, 0x8c, 0x4c, 0x8e, 0x63, 0x2e, + 0xd9, 0x3a, 0x99, 0x31, 0xfe, 0x99, 0x52, 0x35, 0x3d, 0x44, 0xc8, 0x71, 0xd7, 0xea, + 0xeb, 0xdb, 0x1c, 0x3b, 0xcd, 0x8b, 0x66, 0x94, 0xa4, 0xf1, 0x9e, 0x49, 0x92, 0x80, + 0xc8, 0xad, 0x44, 0xa1, 0xc4, 0xee, 0x42, 0x19, 0x92, 0x49, 0x23, 0xae, 0x19, 0x53, + 0xac, 0x7d, 0x92, 0x3e, 0xea, 0x0c, 0x91, 0x3d, 0x1b, 0x2c, 0x22, 0x11, 0x3c, 0x25, + 0x94, 0xe4, 0x3c, 0x55, 0x75, 0xca, 0xf9, 0x4e, 0x31, 0x65, 0x0a, 0x2a}, + {0xc2, 0x27, 0xf9, 0xf7, 0x7f, 0x93, 0xb7, 0x2d, 0x35, 0xa6, 0xd0, 0x17, 0x06, 0x1f, + 0x74, 0xdb, 0x76, 0xaf, 0x55, 0x11, 0xa2, 0xf3, 0x82, 0x59, 0xed, 0x2d, 0x7c, 0x64, + 0x18, 0xe2, 0xf6, 0x4c, 0x3a, 0x79, 0x1c, 0x3c, 0xcd, 0x1a, 0x36, 0xcf, 0x3b, 0xbc, + 0x35, 0x5a, 0xac, 0xbc, 0x9e, 0x2f, 0xab, 0xa6, 0xcd, 0xa8, 0xe9, 0x60, 0xe8, 0x60, + 0x13, 0x1a, 0xea, 0x6d, 0x9b, 0xc3, 0x5d, 0x05, 0xb6, 0x5b, 0x8d, 0xc2, 0x7c, 0x22, + 0x19, 0xb1, 0xab, 0xff, 0x4d, 0x77, 0xbc, 0x4e, 0xe2, 0x07, 0x89, 0x2c, 0xa3, 0xe4, + 0xce, 0x78, 0x3c, 0xa8, 0xb6, 0x24, 0xaa, 0x10, 0x77, 0x30, 0x1a, 0x12}, + {0x97, 0x4a, 0x03, 0x9f, 0x5e, 0x5d, 0xdb, 0xe4, 0x2d, 0xbc, 0x34, 0x30, 0x09, 0xfc, + 0x53, 0xe1, 0xb1, 0xd3, 0x51, 0x95, 0x91, 0x46, 0x05, 0x46, 0x2d, 0xe5, 0x40, 0x7a, + 0x6c, 0xc7, 0x3f, 0x33, 0xc9, 0x83, 0x74, 0xc7, 0x3e, 0x71, 0x59, 0xd6, 0xaf, 0x96, + 0x2b, 0xb8, 0x77, 0xe0, 0xbf, 0x88, 0xd3, 0xbc, 0x97, 0x10, 0x23, 0x28, 0x9e, 0x28, + 0x9b, 0x3a, 0xed, 0x6c, 0x4a, 0xb9, 0x7b, 0x52, 0x2e, 0x48, 0x5b, 0x99, 0x2a, 0x99, + 0x3d, 0x56, 0x01, 0x38, 0x38, 0x6e, 0x7c, 0xd0, 0x05, 0x34, 0xe5, 0xd8, 0x64, 0x2f, + 0xde, 0x35, 0x50, 0x48, 0xf7, 0xa9, 0xa7, 0x20, 0x9b, 0x06, 0x89, 0x6b}, + {0x0d, 0x22, 0x70, 0x62, 0x41, 0xa0, 0x2a, 0x81, 0x4e, 0x5b, 0x24, 0xf9, 0xfa, 0x89, + 0x5a, 0x99, 0x05, 0xef, 0x72, 0x50, 0xce, 0xc4, 0xad, 0xff, 0x73, 0xeb, 0x73, 0xaa, + 0x03, 0x21, 0xbc, 0x23, 0x77, 0xdb, 0xc7, 0xb5, 0x8c, 0xfa, 0x82, 0x40, 0x55, 0xc1, + 0x34, 0xc7, 0xf8, 0x86, 0x86, 0x06, 0x7e, 0xa5, 0xe7, 0xf6, 0xd9, 0xc8, 0xe6, 0x29, + 0xcf, 0x9b, 0x63, 0xa7, 0x08, 0xd3, 0x73, 0x04, 0x05, 0x9e, 0x58, 0x03, 0x26, 0x79, + 0xee, 0xca, 0x92, 0xc4, 0xdc, 0x46, 0x12, 0x42, 0x4b, 0x2b, 0x4f, 0xa9, 0x01, 0xe6, + 0x74, 0xef, 0xa1, 0x02, 0x1a, 0x34, 0x04, 0xde, 0xbf, 0x73, 0x2f, 0x10}, + {0xc6, 0x45, 0x57, 0x7f, 0xab, 0xb9, 0x18, 0xeb, 0x90, 0xc6, 0x87, 0x57, 0xee, 0x8a, + 0x3a, 0x02, 0xa9, 0xaf, 0xf7, 0x2d, 0xda, 0x12, 0x27, 0xb7, 0x3d, 0x01, 0x5c, 0xea, + 0x25, 0x7d, 0x59, 0x36, 0x9a, 0x1c, 0x51, 0xb5, 0xe0, 0xda, 0xb4, 0xa2, 0x06, 0xff, + 0xff, 0x2b, 0x29, 0x60, 0xc8, 0x7a, 0x34, 0x42, 0x50, 0xf5, 0x5d, 0x37, 0x1f, 0x98, + 0x2d, 0xa1, 0x4e, 0xda, 0x25, 0xd7, 0x6b, 0x3f, 0xac, 0x58, 0x60, 0x10, 0x7b, 0x8d, + 0x4d, 0x73, 0x5f, 0x90, 0xc6, 0x6f, 0x9e, 0x57, 0x40, 0xd9, 0x2d, 0x93, 0x02, 0x92, + 0xf9, 0xf8, 0x66, 0x64, 0xd0, 0xd6, 0x60, 0xda, 0x19, 0xcc, 0x7e, 0x7b}, + {0x0d, 0x69, 0x5c, 0x69, 0x3c, 0x37, 0xc2, 0x78, 0x6e, 0x90, 0x42, 0x06, 0x66, 0x2e, + 0x25, 0xdd, 0xd2, 0x2b, 0xe1, 0x4a, 0x44, 0x44, 0x1d, 0x95, 0x56, 0x39, 0x74, 0x01, + 0x76, 0xad, 0x35, 0x42, 0x9b, 0xfa, 0x7c, 0xa7, 0x51, 0x4a, 0xae, 0x6d, 0x50, 0x86, + 0xa3, 0xe7, 0x54, 0x36, 0x26, 0x82, 0xdb, 0x82, 0x2d, 0x8f, 0xcd, 0xff, 0xbb, 0x09, + 0xba, 0xca, 0xf5, 0x1b, 0x66, 0xdc, 0xbe, 0x03, 0xf5, 0x75, 0x89, 0x07, 0x0d, 0xcb, + 0x58, 0x62, 0x98, 0xf2, 0x89, 0x91, 0x54, 0x42, 0x29, 0x49, 0xe4, 0x6e, 0xe3, 0xe2, + 0x23, 0xb4, 0xca, 0xa0, 0xa1, 0x66, 0xf0, 0xcd, 0xb0, 0xe2, 0x7c, 0x0e}, + {0xa3, 0x85, 0x8c, 0xc4, 0x3a, 0x64, 0x94, 0xc4, 0xad, 0x39, 0x61, 0x3c, 0xf4, 0x1d, + 0x36, 0xfd, 0x48, 0x4d, 0xe9, 0x3a, 0xdd, 0x17, 0xdb, 0x09, 0x4a, 0x67, 0xb4, 0x8f, + 0x5d, 0x0a, 0x6e, 0x66, 0xf9, 0x70, 0x4b, 0xd9, 0xdf, 0xfe, 0xa6, 0xfe, 0x2d, 0xba, + 0xfc, 0xc1, 0x51, 0xc0, 0x30, 0xf1, 0x89, 0xab, 0x2f, 0x7f, 0x7e, 0xd4, 0x82, 0x48, + 0xb5, 0xee, 0xec, 0x8a, 0x13, 0x56, 0x52, 0x61, 0x0d, 0xcb, 0x70, 0x48, 0x4e, 0xf6, + 0xbb, 0x2a, 0x6b, 0x8b, 0x45, 0xaa, 0xf0, 0xbc, 0x65, 0xcd, 0x5d, 0x98, 0xe8, 0x75, + 0xba, 0x4e, 0xbe, 0x9a, 0xe4, 0xde, 0x14, 0xd5, 0x10, 0xc8, 0x0b, 0x7f}, + {0x6f, 0x13, 0xf4, 0x26, 0xa4, 0x6b, 0x00, 0xb9, 0x35, 0x30, 0xe0, 0x57, 0x9e, 0x36, + 0x67, 0x8d, 0x28, 0x3c, 0x46, 0x4f, 0xd9, 0xdf, 0xc8, 0xcb, 0xf5, 0xdb, 0xee, 0xf8, + 0xbc, 0x8d, 0x1f, 0x0d, 0xa0, 0x13, 0x72, 0x73, 0xad, 0x9d, 0xac, 0x83, 0x98, 0x2e, + 0xf7, 0x2e, 0xba, 0xf8, 0xf6, 0x9f, 0x57, 0x69, 0xec, 0x43, 0xdd, 0x2e, 0x1e, 0x31, + 0x75, 0xab, 0xc5, 0xde, 0x7d, 0x90, 0x3a, 0x1d, 0xdc, 0x81, 0xd0, 0x3e, 0x31, 0x93, + 0x16, 0xba, 0x80, 0x34, 0x1b, 0x85, 0xad, 0x9f, 0x32, 0x29, 0xcb, 0x21, 0x03, 0x03, + 0x3c, 0x01, 0x28, 0x01, 0xe3, 0xfd, 0x1b, 0xa3, 0x44, 0x1b, 0x01, 0x00}, + {0x0c, 0x6c, 0xc6, 0x3f, 0x6c, 0xa0, 0xdf, 0x3f, 0xd2, 0x0d, 0xd6, 0x4d, 0x8e, 0xe3, + 0x40, 0x5d, 0x71, 0x4d, 0x8e, 0x26, 0x38, 0x8b, 0xe3, 0x7a, 0xe1, 0x57, 0x83, 0x6e, + 0x91, 0x8d, 0xc4, 0x3a, 0x5c, 0xa7, 0x0a, 0x6a, 0x69, 0x1f, 0x56, 0x16, 0x6a, 0xbd, + 0x52, 0x58, 0x5c, 0x72, 0xbf, 0xc1, 0xad, 0x66, 0x79, 0x9a, 0x7f, 0xdd, 0xa8, 0x11, + 0x26, 0x10, 0x85, 0xd2, 0xa2, 0x88, 0xd9, 0x63, 0x2e, 0x23, 0xbd, 0xaf, 0x53, 0x07, + 0x12, 0x00, 0x83, 0xf6, 0xd8, 0xfd, 0xb8, 0xce, 0x2b, 0xe9, 0x91, 0x2b, 0xe7, 0x84, + 0xb3, 0x69, 0x16, 0xf8, 0x66, 0xa0, 0x68, 0x23, 0x2b, 0xd5, 0xfa, 0x33}, + {0x16, 0x1e, 0xe4, 0xc5, 0xc6, 0x49, 0x06, 0x54, 0x35, 0x77, 0x3f, 0x33, 0x30, 0x64, + 0xf8, 0x0a, 0x46, 0xe7, 0x05, 0xf3, 0xd2, 0xfc, 0xac, 0xb2, 0xa7, 0xdc, 0x56, 0xa2, + 0x29, 0xf4, 0xc0, 0x16, 0xe8, 0xcf, 0x22, 0xc4, 0xd0, 0xc8, 0x2c, 0x8d, 0xcb, 0x3a, + 0xa1, 0x05, 0x7b, 0x4f, 0x2b, 0x07, 0x6f, 0xa5, 0xf6, 0xec, 0xe6, 0xb6, 0xfe, 0xa3, + 0xe2, 0x71, 0x0a, 0xb9, 0xcc, 0x55, 0xc3, 0x3c, 0x31, 0x91, 0x3e, 0x90, 0x43, 0x94, + 0xb6, 0xe9, 0xce, 0x37, 0x56, 0x7a, 0xcb, 0x94, 0xa4, 0xb8, 0x44, 0x92, 0xba, 0xba, + 0xa4, 0xd1, 0x7c, 0xc8, 0x68, 0x75, 0xae, 0x6b, 0x42, 0xaf, 0x1e, 0x63}, + {0x9f, 0xfe, 0x66, 0xda, 0x10, 0x04, 0xe9, 0xb3, 0xa6, 0xe5, 0x16, 0x6c, 0x52, 0x4b, + 0xdd, 0x85, 0x83, 0xbf, 0xf9, 0x1e, 0x61, 0x97, 0x3d, 0xbc, 0xb5, 0x19, 0xa9, 0x1e, + 0x8b, 0x64, 0x99, 0x55, 0xe8, 0x0d, 0x70, 0xa3, 0xb9, 0x75, 0xd9, 0x47, 0x52, 0x05, + 0xf8, 0xe2, 0xfb, 0xc5, 0x80, 0x72, 0xe1, 0x5d, 0xe4, 0x32, 0x27, 0x8f, 0x65, 0x53, + 0xb5, 0x80, 0x5f, 0x66, 0x7f, 0x2c, 0x1f, 0x43, 0x19, 0x7b, 0x8f, 0x85, 0x44, 0x63, + 0x02, 0xd6, 0x4a, 0x51, 0xea, 0xa1, 0x2f, 0x35, 0xab, 0x14, 0xd7, 0xa9, 0x90, 0x20, + 0x1a, 0x44, 0x00, 0x89, 0x26, 0x3b, 0x25, 0x91, 0x5f, 0x71, 0x04, 0x7b}, + {0x43, 0xae, 0xf6, 0xac, 0x28, 0xbd, 0xed, 0x83, 0xb4, 0x7a, 0x5c, 0x7d, 0x8b, 0x7c, + 0x35, 0x86, 0x44, 0x2c, 0xeb, 0xb7, 0x69, 0x47, 0x40, 0xc0, 0x3f, 0x58, 0xf6, 0xc2, + 0xf5, 0x7b, 0xb3, 0x59, 0xc6, 0xba, 0xe6, 0xc4, 0x80, 0xc2, 0x76, 0xb3, 0x0b, 0x9b, + 0x1d, 0x6d, 0xdd, 0xd3, 0x0e, 0x97, 0x44, 0xf9, 0x0b, 0x45, 0x58, 0x95, 0x9a, 0xb0, + 0x23, 0xe2, 0xcd, 0x57, 0xfa, 0xac, 0xd0, 0x48, 0x71, 0xe6, 0xab, 0x7d, 0xe4, 0x26, + 0x0f, 0xb6, 0x37, 0x3a, 0x2f, 0x62, 0x97, 0xa1, 0xd1, 0xf1, 0x94, 0x03, 0x96, 0xe9, + 0x7e, 0xce, 0x08, 0x42, 0xdb, 0x3b, 0x6d, 0x33, 0x91, 0x41, 0x23, 0x16}, + {0xf6, 0x7f, 0x26, 0xf6, 0xde, 0x99, 0xe4, 0xb9, 0x43, 0x08, 0x2c, 0x74, 0x7b, 0xca, + 0x72, 0x77, 0xb1, 0xf2, 0xa4, 0xe9, 0x3f, 0x15, 0xa0, 0x23, 0x06, 0x50, 0xd0, 0xd5, + 0xec, 0xdf, 0xdf, 0x2c, 0x40, 0x86, 0xf3, 0x1f, 0xd6, 0x9c, 0x49, 0xdd, 0xa0, 0x25, + 0x36, 0x06, 0xc3, 0x9b, 0xcd, 0x29, 0xc3, 0x3d, 0xd7, 0x3d, 0x02, 0xd8, 0xe2, 0x51, + 0x31, 0x92, 0x3b, 0x20, 0x7a, 0x70, 0x25, 0x4a, 0x6a, 0xed, 0xf6, 0x53, 0x8a, 0x66, + 0xb7, 0x2a, 0xa1, 0x70, 0xd1, 0x1d, 0x58, 0x42, 0x42, 0x30, 0x61, 0x01, 0xe2, 0x3a, + 0x4c, 0x14, 0x00, 0x40, 0xfc, 0x49, 0x8e, 0x24, 0x6d, 0x89, 0x21, 0x57}, + {0xae, 0x1b, 0x18, 0xfd, 0x17, 0x55, 0x6e, 0x0b, 0xb4, 0x63, 0xb9, 0x2b, 0x9f, 0x62, + 0x22, 0x90, 0x25, 0x46, 0x06, 0x32, 0xe9, 0xbc, 0x09, 0x55, 0xda, 0x13, 0x3c, 0xf6, + 0x74, 0xdd, 0x8e, 0x57, 0x4e, 0xda, 0xd0, 0xa1, 0x91, 0x50, 0x5d, 0x28, 0x08, 0x3e, + 0xfe, 0xb5, 0xa7, 0x6f, 0xaa, 0x4b, 0xb3, 0x93, 0x93, 0xe1, 0x7c, 0x17, 0xe5, 0x63, + 0xfd, 0x30, 0xb0, 0xc4, 0xaf, 0x35, 0xc9, 0x03, 0x3d, 0x0c, 0x2b, 0x49, 0xc6, 0x76, + 0x72, 0x99, 0xfc, 0x05, 0xe2, 0xdf, 0xc4, 0xc2, 0xcc, 0x47, 0x3c, 0x3a, 0x62, 0xdd, + 0x84, 0x9b, 0xd2, 0xdc, 0xa2, 0xc7, 0x88, 0x02, 0x59, 0xab, 0xc2, 0x3e}, + {0xb9, 0x7b, 0xd8, 0xe4, 0x7b, 0xd2, 0xa0, 0xa1, 0xed, 0x1a, 0x39, 0x61, 0xeb, 0x4d, + 0x8b, 0xa9, 0x83, 0x9b, 0xcb, 0x73, 0xd0, 0xdd, 0xa0, 0x99, 0xce, 0xca, 0x0f, 0x20, + 0x5a, 0xc2, 0xd5, 0x2d, 0xcb, 0xd1, 0x32, 0xae, 0x09, 0x3a, 0x21, 0xa7, 0xd5, 0xc2, + 0xf5, 0x40, 0xdf, 0x87, 0x2b, 0x0f, 0x29, 0xab, 0x1e, 0xe8, 0xc6, 0xa4, 0xae, 0x0b, + 0x5e, 0xac, 0xdb, 0x6a, 0x6c, 0xf6, 0x1b, 0x0e, 0x7e, 0x88, 0x2c, 0x79, 0xe9, 0xd5, + 0xab, 0xe2, 0x5d, 0x6d, 0x92, 0xcb, 0x18, 0x00, 0x02, 0x1a, 0x1e, 0x5f, 0xae, 0xba, + 0xcd, 0x69, 0xba, 0xbf, 0x5f, 0x8f, 0xe8, 0x5a, 0xb3, 0x48, 0x05, 0x73}, + {0xee, 0xb8, 0xa8, 0xcb, 0xa3, 0x51, 0x35, 0xc4, 0x16, 0x5f, 0x11, 0xb2, 0x1d, 0x6f, + 0xa2, 0x65, 0x50, 0x38, 0x8c, 0xab, 0x52, 0x4f, 0x0f, 0x76, 0xca, 0xb8, 0x1d, 0x41, + 0x3b, 0x44, 0x43, 0x30, 0x34, 0xe3, 0xd6, 0xa1, 0x4b, 0x09, 0x5b, 0x80, 0x19, 0x3f, + 0x35, 0x09, 0x77, 0xf1, 0x3e, 0xbf, 0x2b, 0x70, 0x22, 0x06, 0xcb, 0x06, 0x3f, 0x42, + 0xdd, 0x45, 0x78, 0xd8, 0x77, 0x22, 0x5a, 0x58, 0x62, 0x89, 0xd4, 0x33, 0x82, 0x5f, + 0x8a, 0xa1, 0x7f, 0x25, 0x78, 0xec, 0xb5, 0xc4, 0x98, 0x66, 0xff, 0x41, 0x3e, 0x37, + 0xa5, 0x6f, 0x8e, 0xa7, 0x1f, 0x98, 0xef, 0x50, 0x89, 0x27, 0x56, 0x76}, + {0xc0, 0xc8, 0x1f, 0xd5, 0x59, 0xcf, 0xc3, 0x38, 0xf2, 0xb6, 0x06, 0x05, 0xfd, 0xd2, + 0xed, 0x9b, 0x8f, 0x0e, 0x57, 0xab, 0x9f, 0x10, 0xbf, 0x26, 0xa6, 0x46, 0xb8, 0xc1, + 0xa8, 0x60, 0x41, 0x3f, 0x9d, 0xcf, 0x86, 0xea, 0xa3, 0x73, 0x70, 0xe1, 0xdc, 0x5f, + 0x15, 0x07, 0xb7, 0xfb, 0x8c, 0x3a, 0x8e, 0x8a, 0x83, 0x31, 0xfc, 0xe7, 0x53, 0x48, + 0x16, 0xf6, 0x13, 0xb6, 0x84, 0xf4, 0xbb, 0x28, 0x7c, 0x6c, 0x13, 0x6f, 0x5c, 0x2f, + 0x61, 0xf2, 0xbe, 0x11, 0xdd, 0xf6, 0x07, 0xd1, 0xea, 0xaf, 0x33, 0x6f, 0xde, 0x13, + 0xd2, 0x9a, 0x7e, 0x52, 0x5d, 0xf7, 0x88, 0x81, 0x35, 0xcb, 0x79, 0x1e}, + {0xf1, 0xe3, 0xf7, 0xee, 0xc3, 0x36, 0x34, 0x01, 0xf8, 0x10, 0x9e, 0xfe, 0x7f, 0x6a, + 0x8b, 0x82, 0xfc, 0xde, 0xf9, 0xbc, 0xe5, 0x08, 0xf9, 0x7f, 0x31, 0x38, 0x3b, 0x3a, + 0x1b, 0x95, 0xd7, 0x65, 0x81, 0x81, 0xe0, 0xf5, 0xd8, 0x53, 0xe9, 0x77, 0xd9, 0xde, + 0x9d, 0x29, 0x44, 0x0c, 0xa5, 0x84, 0xe5, 0x25, 0x45, 0x86, 0x0c, 0x2d, 0x6c, 0xdc, + 0xf4, 0xf2, 0xd1, 0x39, 0x2d, 0xb5, 0x8a, 0x47, 0x59, 0xd1, 0x52, 0x92, 0xd3, 0xa4, + 0xa6, 0x66, 0x07, 0xc8, 0x1a, 0x87, 0xbc, 0xe1, 0xdd, 0xe5, 0x6f, 0xc9, 0xc1, 0xa6, + 0x40, 0x6b, 0x2c, 0xb8, 0x14, 0x22, 0x21, 0x1a, 0x41, 0x7a, 0xd8, 0x16}, + {0x15, 0x62, 0x06, 0x42, 0x5a, 0x7e, 0xbd, 0xb3, 0xc1, 0x24, 0x5a, 0x0c, 0xcd, 0xe3, + 0x9b, 0x87, 0xb7, 0x94, 0xf9, 0xd6, 0xb1, 0x5d, 0xc0, 0x57, 0xa6, 0x8c, 0xf3, 0x65, + 0x81, 0x7c, 0xf8, 0x28, 0x83, 0x05, 0x4e, 0xd5, 0xe2, 0xd5, 0xa4, 0xfb, 0xfa, 0x99, + 0xbd, 0x2e, 0xd7, 0xaf, 0x1f, 0xe2, 0x8f, 0x77, 0xe9, 0x6e, 0x73, 0xc2, 0x7a, 0x49, + 0xde, 0x6d, 0x5a, 0x7a, 0x57, 0x0b, 0x99, 0x1f, 0xd6, 0xf7, 0xe8, 0x1b, 0xad, 0x4e, + 0x34, 0xa3, 0x8f, 0x79, 0xea, 0xac, 0xeb, 0x50, 0x1e, 0x7d, 0x52, 0xe0, 0x0d, 0x52, + 0x9e, 0x56, 0xc6, 0x77, 0x3e, 0x6d, 0x4d, 0x53, 0xe1, 0x2f, 0x88, 0x45}, + {0xd6, 0x83, 0x79, 0x75, 0x5d, 0x34, 0x69, 0x66, 0xa6, 0x11, 0xaa, 0x17, 0x11, 0xed, + 0xb6, 0x62, 0x8f, 0x12, 0x5e, 0x98, 0x57, 0x18, 0xdd, 0x7d, 0xdd, 0xf6, 0x26, 0xf6, + 0xb8, 0xe5, 0x8f, 0x68, 0xe4, 0x6f, 0x3c, 0x94, 0x29, 0x99, 0xac, 0xd8, 0xa2, 0x92, + 0x83, 0xa3, 0x61, 0xf1, 0xf9, 0xb5, 0xf3, 0x9a, 0xc8, 0xbe, 0x13, 0xdb, 0x99, 0x26, + 0x74, 0xf0, 0x05, 0xe4, 0x3c, 0x84, 0xcf, 0x7d, 0xc0, 0x32, 0x47, 0x4a, 0x48, 0xd6, + 0x90, 0x6c, 0x99, 0x32, 0x56, 0xca, 0xfd, 0x43, 0x21, 0xd5, 0xe1, 0xc6, 0x5d, 0x91, + 0xc3, 0x28, 0xbe, 0xb3, 0x1b, 0x19, 0x27, 0x73, 0x7e, 0x68, 0x39, 0x67}, + {0xa6, 0x75, 0x56, 0x38, 0x14, 0x20, 0x78, 0xef, 0xe8, 0xa9, 0xfd, 0xaa, 0x30, 0x9f, + 0x64, 0xa2, 0xcb, 0xa8, 0xdf, 0x5c, 0x50, 0xeb, 0xd1, 0x4c, 0xb3, 0xc0, 0x4d, 0x1d, + 0xba, 0x5a, 0x11, 0x46, 0xc0, 0x1a, 0x0c, 0xc8, 0x9d, 0xcc, 0x6d, 0xa6, 0x36, 0xa4, + 0x38, 0x1b, 0xf4, 0x5c, 0xa0, 0x97, 0xc6, 0xd7, 0xdb, 0x95, 0xbe, 0xf3, 0xeb, 0xa7, + 0xab, 0x7d, 0x7e, 0x8d, 0xf6, 0xb8, 0xa0, 0x7d, 0x76, 0xda, 0xb5, 0xc3, 0x53, 0x19, + 0x0f, 0xd4, 0x9b, 0x9e, 0x11, 0x21, 0x73, 0x6f, 0xac, 0x1d, 0x60, 0x59, 0xb2, 0xfe, + 0x21, 0x60, 0xcc, 0x03, 0x4b, 0x4b, 0x67, 0x83, 0x7e, 0x88, 0x5f, 0x5a}, + {0x11, 0x3d, 0xa1, 0x70, 0xcf, 0x01, 0x63, 0x8f, 0xc4, 0xd0, 0x0d, 0x35, 0x15, 0xb8, + 0xce, 0xcf, 0x7e, 0xa4, 0xbc, 0xa4, 0xd4, 0x97, 0x02, 0xf7, 0x34, 0x14, 0x4d, 0xe4, + 0x56, 0xb6, 0x69, 0x36, 0xb9, 0x43, 0xa6, 0xa0, 0xd3, 0x28, 0x96, 0x9e, 0x64, 0x20, + 0xc3, 0xe6, 0x00, 0xcb, 0xc3, 0xb5, 0x32, 0xec, 0x2d, 0x7c, 0x89, 0x02, 0x53, 0x9b, + 0x0c, 0xc7, 0xd1, 0xd5, 0xe2, 0x7a, 0xe3, 0x43, 0x33, 0xe1, 0xa6, 0xed, 0x06, 0x3f, + 0x7e, 0x38, 0xc0, 0x3a, 0xa1, 0x99, 0x51, 0x1d, 0x30, 0x67, 0x11, 0x38, 0x26, 0x36, + 0xf8, 0xd8, 0x5a, 0xbd, 0xbe, 0xe9, 0xd5, 0x4f, 0xcd, 0xe6, 0x21, 0x6a}, + {0x5f, 0xe6, 0x46, 0x30, 0x0a, 0x17, 0xc6, 0xf1, 0x24, 0x35, 0xd2, 0x00, 0x2a, 0x2a, + 0x71, 0x58, 0x55, 0xb7, 0x82, 0x8c, 0x3c, 0xbd, 0xdb, 0x69, 0x57, 0xff, 0x95, 0xa1, + 0xf1, 0xf9, 0x6b, 0x58, 0xe3, 0xb2, 0x99, 0x66, 0x12, 0x29, 0x41, 0xef, 0x01, 0x13, + 0x8d, 0x70, 0x47, 0x08, 0xd3, 0x71, 0xbd, 0xb0, 0x82, 0x11, 0xd0, 0x32, 0x54, 0x32, + 0x36, 0x8b, 0x1e, 0x00, 0x07, 0x1b, 0x37, 0x45, 0x0b, 0x79, 0xf8, 0x5e, 0x8d, 0x08, + 0xdb, 0xa6, 0xe5, 0x37, 0x09, 0x61, 0xdc, 0xf0, 0x78, 0x52, 0xb8, 0x6e, 0xa1, 0x61, + 0xd2, 0x49, 0x03, 0xac, 0x79, 0x21, 0xe5, 0x90, 0x37, 0xb0, 0xaf, 0x0e}, + {0x2f, 0x04, 0x48, 0x37, 0xc1, 0x55, 0x05, 0x96, 0x11, 0xaa, 0x0b, 0x82, 0xe6, 0x41, + 0x9a, 0x21, 0x0c, 0x6d, 0x48, 0x73, 0x38, 0xf7, 0x81, 0x1c, 0x61, 0xc6, 0x02, 0x5a, + 0x67, 0xcc, 0x9a, 0x30, 0x1d, 0xae, 0x75, 0x0f, 0x5e, 0x80, 0x40, 0x51, 0x30, 0xcc, + 0x62, 0x26, 0xe3, 0xfb, 0x02, 0xec, 0x6d, 0x39, 0x92, 0xea, 0x1e, 0xdf, 0xeb, 0x2c, + 0xb3, 0x5b, 0x43, 0xc5, 0x44, 0x33, 0xae, 0x44, 0xee, 0x43, 0xa5, 0xbb, 0xb9, 0x89, + 0xf2, 0x9c, 0x42, 0x71, 0xc9, 0x5a, 0x9d, 0x0e, 0x76, 0xf3, 0xaa, 0x60, 0x93, 0x4f, + 0xc6, 0xe5, 0x82, 0x1d, 0x8f, 0x67, 0x94, 0x7f, 0x1b, 0x22, 0xd5, 0x62}, + {0x6d, 0x93, 0xd0, 0x18, 0x9c, 0x29, 0x4c, 0x52, 0x0c, 0x1a, 0x0c, 0x8a, 0x6c, 0xb5, + 0x6b, 0xc8, 0x31, 0x86, 0x4a, 0xdb, 0x2e, 0x05, 0x75, 0xa3, 0x62, 0x45, 0x75, 0xbc, + 0xe4, 0xfd, 0x0e, 0x5c, 0x3c, 0x7a, 0xf7, 0x3a, 0x26, 0xd4, 0x85, 0x75, 0x4d, 0x14, + 0xe9, 0xfe, 0x11, 0x7b, 0xae, 0xdf, 0x3d, 0x19, 0xf7, 0x59, 0x80, 0x70, 0x06, 0xa5, + 0x37, 0x20, 0x92, 0x83, 0x53, 0x9a, 0xf2, 0x14, 0xf5, 0xd7, 0xb2, 0x25, 0xdc, 0x7e, + 0x71, 0xdf, 0x40, 0x30, 0xb5, 0x99, 0xdb, 0x70, 0xf9, 0x21, 0x62, 0x4c, 0xed, 0xc3, + 0xb7, 0x34, 0x92, 0xda, 0x3e, 0x09, 0xee, 0x7b, 0x5c, 0x36, 0x72, 0x5e}, + {0x7f, 0x21, 0x71, 0x45, 0x07, 0xfc, 0x5b, 0x57, 0x5b, 0xd9, 0x94, 0x06, 0x5d, 0x67, + 0x79, 0x37, 0x33, 0x1e, 0x19, 0xf4, 0xbb, 0x37, 0x0a, 0x9a, 0xbc, 0xea, 0xb4, 0x47, + 0x4c, 0x10, 0xf1, 0x77, 0x3e, 0xb3, 0x08, 0x2f, 0x06, 0x39, 0x93, 0x7d, 0xbe, 0x32, + 0x9f, 0xdf, 0xe5, 0x59, 0x96, 0x5b, 0xfd, 0xbd, 0x9e, 0x1f, 0xad, 0x3d, 0xff, 0xac, + 0xb7, 0x49, 0x73, 0xcb, 0x55, 0x05, 0xb2, 0x70, 0x4c, 0x2c, 0x11, 0x55, 0xc5, 0x13, + 0x51, 0xbe, 0xcd, 0x1f, 0x88, 0x9a, 0x3a, 0x42, 0x88, 0x66, 0x47, 0x3b, 0x50, 0x5e, + 0x85, 0x77, 0x66, 0x44, 0x4a, 0x40, 0x06, 0x4a, 0x8f, 0x39, 0x34, 0x0e}, + {0xe8, 0xbd, 0xce, 0x3e, 0xd9, 0x22, 0x7d, 0xb6, 0x07, 0x2f, 0x82, 0x27, 0x41, 0xe8, + 0xb3, 0x09, 0x8d, 0x6d, 0x5b, 0xb0, 0x1f, 0xa6, 0x3f, 0x74, 0x72, 0x23, 0x36, 0x8a, + 0x36, 0x05, 0x54, 0x5e, 0x28, 0x19, 0x4b, 0x3e, 0x09, 0x0b, 0x93, 0x18, 0x40, 0xf6, + 0xf3, 0x73, 0x0e, 0xe1, 0xe3, 0x7d, 0x6f, 0x5d, 0x39, 0x73, 0xda, 0x17, 0x32, 0xf4, + 0x3e, 0x9c, 0x37, 0xca, 0xd6, 0xde, 0x8a, 0x6f, 0x9a, 0xb2, 0xb7, 0xfd, 0x3d, 0x12, + 0x40, 0xe3, 0x91, 0xb2, 0x1a, 0xa2, 0xe1, 0x97, 0x7b, 0x48, 0x9e, 0x94, 0xe6, 0xfd, + 0x02, 0x7d, 0x96, 0xf9, 0x97, 0xde, 0xd3, 0xc8, 0x2e, 0xe7, 0x0d, 0x78}, + {0xbc, 0xe7, 0x9a, 0x08, 0x45, 0x85, 0xe2, 0x0a, 0x06, 0x4d, 0x7f, 0x1c, 0xcf, 0xde, + 0x8d, 0x38, 0xb8, 0x11, 0x48, 0x0a, 0x51, 0x15, 0xac, 0x38, 0xe4, 0x8c, 0x92, 0x71, + 0xf6, 0x8b, 0xb2, 0x0e, 0x72, 0x27, 0xf4, 0x00, 0xf3, 0xea, 0x1f, 0x67, 0xaa, 0x41, + 0x8c, 0x2a, 0x2a, 0xeb, 0x72, 0x8f, 0x92, 0x32, 0x37, 0x97, 0xd7, 0x7f, 0xa1, 0x29, + 0xa6, 0x87, 0xb5, 0x32, 0xad, 0xc6, 0xef, 0x1d, 0xa7, 0x95, 0x51, 0xef, 0x1a, 0xbe, + 0x5b, 0xaf, 0xed, 0x15, 0x7b, 0x91, 0x77, 0x12, 0x8c, 0x14, 0x2e, 0xda, 0xe5, 0x7a, + 0xfb, 0xf7, 0x91, 0x29, 0x67, 0x28, 0xdd, 0xf8, 0x1b, 0x20, 0x7d, 0x46}, + {0xad, 0x4f, 0xef, 0x74, 0x9a, 0x91, 0xfe, 0x95, 0xa2, 0x08, 0xa3, 0xf6, 0xec, 0x7b, + 0x82, 0x3a, 0x01, 0x7b, 0xa4, 0x09, 0xd3, 0x01, 0x4e, 0x96, 0x97, 0xc7, 0xa3, 0x5b, + 0x4f, 0x3c, 0xc4, 0x71, 0xa9, 0xe7, 0x7a, 0x56, 0xbd, 0xf4, 0x1e, 0xbc, 0xbd, 0x98, + 0x44, 0xd6, 0xb2, 0x4c, 0x62, 0x3f, 0xc8, 0x4e, 0x1f, 0x2c, 0xd2, 0x64, 0x10, 0xe4, + 0x01, 0x40, 0x38, 0xba, 0xa5, 0xc5, 0xf9, 0x2e, 0xcd, 0x74, 0x9e, 0xfa, 0xf6, 0x6d, + 0xfd, 0xb6, 0x7a, 0x26, 0xaf, 0xe4, 0xbc, 0x78, 0x82, 0xf1, 0x0e, 0x99, 0xef, 0xf1, + 0xd0, 0xb3, 0x55, 0x82, 0x93, 0xf2, 0xc5, 0x90, 0xa3, 0x8c, 0x75, 0x5a}, + {0x95, 0x24, 0x46, 0xd9, 0x10, 0x27, 0xb7, 0xa2, 0x03, 0x50, 0x7d, 0xd5, 0xd2, 0xc6, + 0xa8, 0x3a, 0xca, 0x87, 0xb4, 0xa0, 0xbf, 0x00, 0xd4, 0xe3, 0xec, 0x72, 0xeb, 0xb3, + 0x44, 0xe2, 0xba, 0x2d, 0x94, 0xdc, 0x61, 0x1d, 0x8b, 0x91, 0xe0, 0x8c, 0x66, 0x30, + 0x81, 0x9a, 0x46, 0x36, 0xed, 0x8d, 0xd3, 0xaa, 0xe8, 0xaf, 0x29, 0xa8, 0xe6, 0xd4, + 0x3f, 0xd4, 0x39, 0xf6, 0x27, 0x80, 0x73, 0x0a, 0xcc, 0xe1, 0xff, 0x57, 0x2f, 0x4a, + 0x0f, 0x98, 0x43, 0x98, 0x83, 0xe1, 0x0d, 0x0d, 0x67, 0x00, 0xfd, 0x15, 0xfb, 0x49, + 0x4a, 0x3f, 0x5c, 0x10, 0x9c, 0xa6, 0x26, 0x51, 0x63, 0xca, 0x98, 0x26}, + {0x78, 0xba, 0xb0, 0x32, 0x88, 0x31, 0x65, 0xe7, 0x8b, 0xff, 0x5c, 0x92, 0xf7, 0x31, + 0x18, 0x38, 0xcc, 0x1f, 0x29, 0xa0, 0x91, 0x1b, 0xa8, 0x08, 0x07, 0xeb, 0xca, 0x49, + 0xcc, 0x3d, 0xb4, 0x1f, 0x0e, 0xd9, 0x3d, 0x5e, 0x2f, 0x70, 0x3d, 0x2e, 0x86, 0x53, + 0xd2, 0xe4, 0x18, 0x09, 0x3f, 0x9e, 0x6a, 0xa9, 0x4d, 0x02, 0xf6, 0x3e, 0x77, 0x5e, + 0x32, 0x33, 0xfa, 0x4a, 0x0c, 0x4b, 0x00, 0x3c, 0x2b, 0xb8, 0xf4, 0x06, 0xac, 0x46, + 0xa9, 0x9a, 0xf3, 0xc4, 0x06, 0xa8, 0xa5, 0x84, 0xa2, 0x1c, 0x87, 0x47, 0xcd, 0xc6, + 0x5f, 0x26, 0xd3, 0x3e, 0x17, 0xd2, 0x1f, 0xcd, 0x01, 0xfd, 0x43, 0x6b}, + {0x44, 0xc5, 0x97, 0x46, 0x4b, 0x5d, 0xa7, 0xc7, 0xbf, 0xff, 0x0f, 0xdf, 0x48, 0xf8, + 0xfd, 0x15, 0x5a, 0x78, 0x46, 0xaa, 0xeb, 0xb9, 0x68, 0x28, 0x14, 0xf7, 0x52, 0x5b, + 0x10, 0xd7, 0x68, 0x5a, 0xf3, 0x0e, 0x76, 0x3e, 0x58, 0x42, 0xc7, 0xb5, 0x90, 0xb9, + 0x0a, 0xee, 0xb9, 0x52, 0xdc, 0x75, 0x3f, 0x92, 0x2b, 0x07, 0xc2, 0x27, 0x14, 0xbf, + 0xf0, 0xd9, 0xf0, 0x6f, 0x2d, 0x0b, 0x42, 0x73, 0x06, 0x1e, 0x85, 0x9e, 0xcb, 0xf6, + 0x2c, 0xaf, 0xc4, 0x38, 0x22, 0xc6, 0x13, 0x39, 0x59, 0x8f, 0x73, 0xf3, 0xfb, 0x99, + 0x96, 0xb8, 0x8a, 0xda, 0x9e, 0xbc, 0x34, 0xea, 0x2f, 0x63, 0xb5, 0x3d}, + {0xd8, 0xd9, 0x5d, 0xf7, 0x2b, 0xee, 0x6e, 0xf4, 0xa5, 0x59, 0x67, 0x39, 0xf6, 0xb1, + 0x17, 0x0d, 0x73, 0x72, 0x9e, 0x49, 0x31, 0xd1, 0xf2, 0x1b, 0x13, 0x5f, 0xd7, 0x49, + 0xdf, 0x1a, 0x32, 0x04, 0xd5, 0x25, 0x98, 0x82, 0xb1, 0x90, 0x49, 0x2e, 0x91, 0x89, + 0x9a, 0x3e, 0x87, 0xeb, 0xea, 0xed, 0xf8, 0x4a, 0x70, 0x4c, 0x39, 0x3d, 0xf0, 0xee, + 0x0e, 0x2b, 0xdf, 0x95, 0xa4, 0x7e, 0x19, 0x59, 0xae, 0x5a, 0xe5, 0xe4, 0x19, 0x60, + 0xe1, 0x04, 0xe9, 0x92, 0x2f, 0x7e, 0x7a, 0x43, 0x7b, 0xe7, 0xa4, 0x9a, 0x15, 0x6f, + 0xc1, 0x2d, 0xce, 0xc7, 0xc0, 0x0c, 0xd7, 0xf4, 0xc1, 0xfd, 0xea, 0x45}, + {0x2b, 0xd7, 0x45, 0x80, 0x85, 0x01, 0x84, 0x69, 0x51, 0x06, 0x2f, 0xcf, 0xa2, 0xfa, + 0x22, 0x4c, 0xc6, 0x2d, 0x22, 0x6b, 0x65, 0x36, 0x1a, 0x94, 0xde, 0xda, 0x62, 0x03, + 0xc8, 0xeb, 0x5e, 0x5a, 0xed, 0xb1, 0xcc, 0xcf, 0x24, 0x46, 0x0e, 0xb6, 0x95, 0x03, + 0x5c, 0xbd, 0x92, 0xc2, 0xdb, 0x59, 0xc9, 0x81, 0x04, 0xdc, 0x1d, 0x9d, 0xa0, 0x31, + 0x40, 0xd9, 0x56, 0x5d, 0xea, 0xce, 0x73, 0x3f, 0xc6, 0x8d, 0x4e, 0x0a, 0xd1, 0xbf, + 0xa7, 0xb7, 0x39, 0xb3, 0xc9, 0x44, 0x7e, 0x00, 0x57, 0xbe, 0xfa, 0xae, 0x57, 0x15, + 0x7f, 0x20, 0xc1, 0x60, 0xdb, 0x18, 0x62, 0x26, 0x91, 0x88, 0x05, 0x26}, + {0x04, 0xff, 0x60, 0x83, 0xa6, 0x04, 0xf7, 0x59, 0xf4, 0xe6, 0x61, 0x76, 0xde, 0x3f, + 0xd9, 0xc3, 0x51, 0x35, 0x87, 0x12, 0x73, 0x2a, 0x1b, 0x83, 0x57, 0x5d, 0x61, 0x4e, + 0x2e, 0x0c, 0xad, 0x54, 0x42, 0xe5, 0x76, 0xc6, 0x3c, 0x8e, 0x81, 0x4c, 0xad, 0xcc, + 0xce, 0x03, 0x93, 0x2c, 0x42, 0x5e, 0x08, 0x9f, 0x12, 0xb4, 0xca, 0xcc, 0x07, 0xec, + 0xb8, 0x43, 0x44, 0xb2, 0x10, 0xfa, 0xed, 0x0d, 0x2a, 0x52, 0x2b, 0xb8, 0xd5, 0x67, + 0x3b, 0xee, 0xeb, 0xc1, 0xa5, 0x9f, 0x46, 0x63, 0xf1, 0x36, 0xd3, 0x9f, 0xc1, 0x6e, + 0xf2, 0xd2, 0xb4, 0xa5, 0x08, 0x94, 0x7a, 0xa7, 0xba, 0xb2, 0xec, 0x62}, + {0x3d, 0x2b, 0x15, 0x61, 0x52, 0x79, 0xed, 0xe5, 0xd1, 0xd7, 0xdd, 0x0e, 0x7d, 0x35, + 0x62, 0x49, 0x71, 0x4c, 0x6b, 0xb9, 0xd0, 0xc8, 0x82, 0x74, 0xbe, 0xd8, 0x66, 0xa9, + 0x19, 0xf9, 0x59, 0x2e, 0x74, 0x28, 0xb6, 0xaf, 0x36, 0x28, 0x07, 0x92, 0xa5, 0x04, + 0xe1, 0x79, 0x85, 0x5e, 0xcd, 0x5f, 0x4a, 0xa1, 0x30, 0xc6, 0xad, 0x01, 0xad, 0x5a, + 0x98, 0x3f, 0x66, 0x75, 0x50, 0x3d, 0x91, 0x61, 0xda, 0x31, 0x32, 0x1a, 0x36, 0x2d, + 0xc6, 0x0d, 0x70, 0x02, 0x20, 0x94, 0x32, 0x58, 0x47, 0xfa, 0xce, 0x94, 0x95, 0x3f, + 0x51, 0x01, 0xd8, 0x02, 0x5c, 0x5d, 0xc0, 0x31, 0xa1, 0xc2, 0xdb, 0x3d}, + {0x4b, 0xc5, 0x5e, 0xce, 0xf9, 0x0f, 0xdc, 0x9a, 0x0d, 0x13, 0x2f, 0x8c, 0x6b, 0x2a, + 0x9c, 0x03, 0x15, 0x95, 0xf8, 0xf0, 0xc7, 0x07, 0x80, 0x02, 0x6b, 0xb3, 0x04, 0xac, + 0x14, 0x83, 0x96, 0x78, 0x14, 0xbb, 0x96, 0x27, 0xa2, 0x57, 0xaa, 0xf3, 0x21, 0xda, + 0x07, 0x9b, 0xb7, 0xba, 0x3a, 0x88, 0x1c, 0x39, 0xa0, 0x31, 0x18, 0xe2, 0x4b, 0xe5, + 0xf9, 0x05, 0x32, 0xd8, 0x38, 0xfb, 0xe7, 0x5e, 0x8e, 0x6a, 0x44, 0x41, 0xcb, 0xfd, + 0x8d, 0x53, 0xf9, 0x37, 0x49, 0x43, 0xa9, 0xfd, 0xac, 0xa5, 0x78, 0x8c, 0x3c, 0x26, + 0x8d, 0x90, 0xaf, 0x46, 0x09, 0x0d, 0xca, 0x9b, 0x3c, 0x63, 0xd0, 0x61}, + {0x66, 0x25, 0xdb, 0xff, 0x35, 0x49, 0x74, 0x63, 0xbb, 0x68, 0x0b, 0x78, 0x89, 0x6b, + 0xbd, 0xc5, 0x03, 0xec, 0x3e, 0x55, 0x80, 0x32, 0x1b, 0x6f, 0xf5, 0xd7, 0xae, 0x47, + 0xd8, 0x5f, 0x96, 0x6e, 0xdf, 0x73, 0xfc, 0xf8, 0xbc, 0x28, 0xa3, 0xad, 0xfc, 0x37, + 0xf0, 0xa6, 0x5d, 0x69, 0x84, 0xee, 0x09, 0xa9, 0xc2, 0x38, 0xdb, 0xb4, 0x7f, 0x63, + 0xdc, 0x7b, 0x06, 0xf8, 0x2d, 0xac, 0x23, 0x5b, 0x7b, 0x52, 0x80, 0xee, 0x53, 0xb9, + 0xd2, 0x9a, 0x8d, 0x6d, 0xde, 0xfa, 0xaa, 0x19, 0x8f, 0xe8, 0xcf, 0x82, 0x0e, 0x15, + 0x04, 0x17, 0x71, 0x0e, 0xdc, 0xde, 0x95, 0xdd, 0xb9, 0xbb, 0xb9, 0x79}, + {0xc2, 0x26, 0x31, 0x6a, 0x40, 0x55, 0xb3, 0xeb, 0x93, 0xc3, 0xc8, 0x68, 0xa8, 0x83, + 0x63, 0xd2, 0x82, 0x7a, 0xb9, 0xe5, 0x29, 0x64, 0x0c, 0x6c, 0x47, 0x21, 0xfd, 0xc9, + 0x58, 0xf1, 0x65, 0x50, 0x74, 0x73, 0x9f, 0x8e, 0xae, 0x7d, 0x99, 0xd1, 0x16, 0x08, + 0xbb, 0xcf, 0xf8, 0xa2, 0x32, 0xa0, 0x0a, 0x5f, 0x44, 0x6d, 0x12, 0xba, 0x6c, 0xcd, + 0x34, 0xb8, 0xcc, 0x0a, 0x46, 0x11, 0xa8, 0x1b, 0x54, 0x99, 0x42, 0x0c, 0xfb, 0x69, + 0x81, 0x70, 0x67, 0xcf, 0x6e, 0xd7, 0xac, 0x00, 0x46, 0xe1, 0xba, 0x45, 0xe6, 0x70, + 0x8a, 0xb9, 0xaa, 0x2e, 0xf2, 0xfa, 0xa4, 0x58, 0x9e, 0xf3, 0x81, 0x39}, + {0x93, 0x0a, 0x23, 0x59, 0x75, 0x8a, 0xfb, 0x18, 0x5d, 0xf4, 0xe6, 0x60, 0x69, 0x8f, + 0x16, 0x1d, 0xb5, 0x3c, 0xa9, 0x14, 0x45, 0xa9, 0x85, 0x3a, 0xfd, 0xd0, 0xac, 0x05, + 0x37, 0x08, 0xdc, 0x38, 0xde, 0x6f, 0xe6, 0x6d, 0xa5, 0xdf, 0x45, 0xc8, 0x3a, 0x48, + 0x40, 0x2c, 0x00, 0xa5, 0x52, 0xe1, 0x32, 0xf6, 0xb4, 0xc7, 0x63, 0xe1, 0xd2, 0xe9, + 0x65, 0x1b, 0xbc, 0xdc, 0x2e, 0x45, 0xf4, 0x30, 0x40, 0x97, 0x75, 0xc5, 0x82, 0x27, + 0x6d, 0x85, 0xcc, 0xbe, 0x9c, 0xf9, 0x69, 0x45, 0x13, 0xfa, 0x71, 0x4e, 0xea, 0xc0, + 0x73, 0xfc, 0x44, 0x88, 0x69, 0x24, 0x3f, 0x59, 0x1a, 0x9a, 0x2d, 0x63}, + {0xa6, 0xcb, 0x07, 0xb8, 0x15, 0x6b, 0xbb, 0xf6, 0xd7, 0xf0, 0x54, 0xbc, 0xdf, 0xc7, + 0x23, 0x18, 0x0b, 0x67, 0x29, 0x6e, 0x03, 0x97, 0x1d, 0xbb, 0x57, 0x4a, 0xed, 0x47, + 0x88, 0xf4, 0x24, 0x0b, 0xa7, 0x84, 0x0c, 0xed, 0x11, 0xfd, 0x09, 0xbf, 0x3a, 0x69, + 0x9f, 0x0d, 0x81, 0x71, 0xf0, 0x63, 0x79, 0x87, 0xcf, 0x57, 0x2d, 0x8c, 0x90, 0x21, + 0xa2, 0x4b, 0xf6, 0x8a, 0xf2, 0x7d, 0x5a, 0x3a, 0xc7, 0xea, 0x1b, 0x51, 0xbe, 0xd4, + 0xda, 0xdc, 0xf2, 0xcc, 0x26, 0xed, 0x75, 0x80, 0x53, 0xa4, 0x65, 0x9a, 0x5f, 0x00, + 0x9f, 0xff, 0x9c, 0xe1, 0x63, 0x1f, 0x48, 0x75, 0x44, 0xf7, 0xfc, 0x34}, + {0xca, 0x67, 0x97, 0x78, 0x4c, 0xe0, 0x97, 0xc1, 0x7d, 0x46, 0xd9, 0x38, 0xcb, 0x4d, + 0x71, 0xb8, 0xa8, 0x5f, 0xf9, 0x83, 0x82, 0x88, 0xde, 0x55, 0xf7, 0x63, 0xfa, 0x4d, + 0x16, 0xdc, 0x3b, 0x3d, 0x98, 0xaa, 0xcf, 0x78, 0xab, 0x1d, 0xbb, 0xa5, 0xf2, 0x72, + 0x0b, 0x19, 0x67, 0xa2, 0xed, 0x5c, 0x8e, 0x60, 0x92, 0x0a, 0x11, 0xc9, 0x09, 0x93, + 0xb0, 0x74, 0xb3, 0x2f, 0x04, 0xa3, 0x19, 0x01, 0x7d, 0x17, 0xc2, 0xe8, 0x9c, 0xd8, + 0xa2, 0x67, 0xc1, 0xd0, 0x95, 0x68, 0xf6, 0xa5, 0x9d, 0x66, 0xb0, 0xa2, 0x82, 0xb2, + 0xe5, 0x98, 0x65, 0xf5, 0x73, 0x0a, 0xe2, 0xed, 0xf1, 0x88, 0xc0, 0x56}, + {0x17, 0x6e, 0xa8, 0x10, 0x11, 0x3d, 0x6d, 0x33, 0xfa, 0xb2, 0x75, 0x0b, 0x32, 0x88, + 0xf3, 0xd7, 0x88, 0x29, 0x07, 0x25, 0x76, 0x33, 0x15, 0xf9, 0x87, 0x8b, 0x10, 0x99, + 0x6b, 0x4c, 0x67, 0x09, 0x02, 0x8f, 0xf3, 0x24, 0xac, 0x5f, 0x1b, 0x58, 0xbd, 0x0c, + 0xe3, 0xba, 0xfe, 0xe9, 0x0b, 0xa9, 0xf0, 0x92, 0xcf, 0x8a, 0x02, 0x69, 0x21, 0x9a, + 0x8f, 0x03, 0x59, 0x83, 0xa4, 0x7e, 0x8b, 0x03, 0xf8, 0x6f, 0x31, 0x99, 0x21, 0xf8, + 0x4e, 0x9f, 0x4f, 0x8d, 0xa7, 0xea, 0x82, 0xd2, 0x49, 0x2f, 0x74, 0x31, 0xef, 0x5a, + 0xab, 0xa5, 0x71, 0x09, 0x65, 0xeb, 0x69, 0x59, 0x02, 0x31, 0x5e, 0x6e}, + {0xfb, 0x93, 0xe5, 0x87, 0xf5, 0x62, 0x6c, 0xb1, 0x71, 0x3e, 0x5d, 0xca, 0xde, 0xed, + 0x99, 0x49, 0x6d, 0x3e, 0xcc, 0x14, 0xe0, 0xc1, 0x91, 0xb4, 0xa8, 0xdb, 0xa8, 0x89, + 0x47, 0x11, 0xf5, 0x08, 0x22, 0x62, 0x06, 0x63, 0x0e, 0xfb, 0x04, 0x33, 0x3f, 0xba, + 0xac, 0x87, 0x89, 0x06, 0x35, 0xfb, 0xa3, 0x61, 0x10, 0x8c, 0x77, 0x24, 0x19, 0xbd, + 0x20, 0x86, 0x83, 0xd1, 0x43, 0xad, 0x58, 0x30, 0xd0, 0x63, 0x76, 0xe5, 0xfd, 0x0f, + 0x3c, 0x32, 0x10, 0xa6, 0x2e, 0xa2, 0x38, 0xdf, 0xc3, 0x05, 0x9a, 0x4f, 0x99, 0xac, + 0xbd, 0x8a, 0xc7, 0xbd, 0x99, 0xdc, 0xe3, 0xef, 0xa4, 0x9f, 0x54, 0x26}, + {0xd6, 0xf9, 0x6b, 0x1e, 0x46, 0x5a, 0x1d, 0x74, 0x81, 0xa5, 0x77, 0x77, 0xfc, 0xb3, + 0x05, 0x23, 0xd9, 0xd3, 0x74, 0x64, 0xa2, 0x74, 0x55, 0xd4, 0xff, 0xe0, 0x01, 0x64, + 0xdc, 0xe1, 0x26, 0x19, 0x6e, 0x66, 0x3f, 0xaf, 0x49, 0x85, 0x46, 0xdb, 0xa5, 0x0e, + 0x4a, 0xf1, 0x04, 0xcf, 0x7f, 0xd7, 0x47, 0x0c, 0xba, 0xa4, 0xf7, 0x3f, 0xf2, 0x3d, + 0x85, 0x3c, 0xce, 0x32, 0xe1, 0xdf, 0x10, 0x3a, 0xa0, 0xce, 0x17, 0xea, 0x8a, 0x4e, + 0x7f, 0xe0, 0xfd, 0xc1, 0x1f, 0x3a, 0x46, 0x15, 0xd5, 0x2f, 0xf1, 0xc0, 0xf2, 0x31, + 0xfd, 0x22, 0x53, 0x17, 0x15, 0x5d, 0x1e, 0x86, 0x1d, 0xd0, 0xa1, 0x1f}, + {0x32, 0x98, 0x59, 0x7d, 0x94, 0x55, 0x80, 0xcc, 0x20, 0x55, 0xf1, 0x37, 0xda, 0x56, + 0x46, 0x1e, 0x20, 0x93, 0x05, 0x4e, 0x74, 0xf7, 0xf6, 0x99, 0x33, 0xcf, 0x75, 0x6a, + 0xbc, 0x63, 0x35, 0x77, 0xab, 0x94, 0xdf, 0xd1, 0x00, 0xac, 0xdc, 0x38, 0xe9, 0x0d, + 0x08, 0xd1, 0xdd, 0x2b, 0x71, 0x2e, 0x62, 0xe2, 0xd5, 0xfd, 0x3e, 0xe9, 0x13, 0x7f, + 0xe5, 0x01, 0x9a, 0xee, 0x18, 0xed, 0xfc, 0x73, 0xb3, 0x9c, 0x13, 0x63, 0x08, 0xe9, + 0xb1, 0x06, 0xcd, 0x3e, 0xa0, 0xc5, 0x67, 0xda, 0x93, 0xa4, 0x32, 0x89, 0x63, 0xad, + 0xc8, 0xce, 0x77, 0x8d, 0x44, 0x4f, 0x86, 0x1b, 0x70, 0x6b, 0x42, 0x1f}, + {0x01, 0x1c, 0x91, 0x41, 0x4c, 0x26, 0xc9, 0xef, 0x25, 0x2c, 0xa2, 0x17, 0xb8, 0xb7, + 0xa3, 0xf1, 0x47, 0x14, 0x0f, 0xf3, 0x6b, 0xda, 0x75, 0x58, 0x90, 0xb0, 0x31, 0x1d, + 0x27, 0xf5, 0x1a, 0x4e, 0x52, 0x25, 0xa1, 0x91, 0xc8, 0x35, 0x7e, 0xf1, 0x76, 0x9c, + 0x5e, 0x57, 0x53, 0x81, 0x6b, 0xb7, 0x3e, 0x72, 0x9b, 0x0d, 0x6f, 0x40, 0x83, 0xfa, + 0x38, 0xe4, 0xa7, 0x3f, 0x1b, 0xbb, 0x76, 0x0b, 0x9b, 0x93, 0x92, 0x7f, 0xf9, 0xc1, + 0xb8, 0x08, 0x6e, 0xab, 0x44, 0xd4, 0xcb, 0x71, 0x67, 0xbe, 0x17, 0x80, 0xbb, 0x99, + 0x63, 0x64, 0xe5, 0x22, 0x55, 0xa9, 0x72, 0xb7, 0x1e, 0xd6, 0x6d, 0x7b}, + {0x92, 0x3d, 0xf3, 0x50, 0xe8, 0xc1, 0xad, 0xb7, 0xcf, 0xd5, 0x8c, 0x60, 0x4f, 0xfa, + 0x98, 0x79, 0xdb, 0x5b, 0xfc, 0x8d, 0xbd, 0x2d, 0x96, 0xad, 0x4f, 0x2f, 0x1d, 0xaf, + 0xce, 0x9b, 0x3e, 0x70, 0xc7, 0xd2, 0x01, 0xab, 0xf9, 0xab, 0x30, 0x57, 0x18, 0x3b, + 0x14, 0x40, 0xdc, 0x76, 0xfb, 0x16, 0x81, 0xb2, 0xcb, 0xa0, 0x65, 0xbe, 0x6c, 0x86, + 0xfe, 0x6a, 0xff, 0x9b, 0x65, 0x9b, 0xfa, 0x53, 0x55, 0x54, 0x88, 0x94, 0xe9, 0xc8, + 0x14, 0x6c, 0xe5, 0xd4, 0xae, 0x65, 0x66, 0x5d, 0x3a, 0x84, 0xf1, 0x5a, 0xd6, 0xbc, + 0x3e, 0xb7, 0x1b, 0x18, 0x50, 0x1f, 0xc6, 0xc4, 0xe5, 0x93, 0x8d, 0x39}, + {0xf3, 0x48, 0xe2, 0x33, 0x67, 0xd1, 0x4b, 0x1c, 0x5f, 0x0a, 0xbf, 0x15, 0x87, 0x12, + 0x9e, 0xbd, 0x76, 0x03, 0x0b, 0xa1, 0xf0, 0x8c, 0x3f, 0xd4, 0x13, 0x1b, 0x19, 0xdf, + 0x5d, 0x9b, 0xb0, 0x53, 0xf2, 0xe3, 0xe7, 0xd2, 0x60, 0x7c, 0x87, 0xc3, 0xb1, 0x8b, + 0x82, 0x30, 0xa0, 0xaa, 0x34, 0x3b, 0x38, 0xf1, 0x9e, 0x73, 0xe7, 0x26, 0x3e, 0x28, + 0x77, 0x05, 0xc3, 0x02, 0x90, 0x9c, 0x9c, 0x69, 0xcc, 0xf1, 0x46, 0x59, 0x23, 0xa7, + 0x06, 0xf3, 0x7d, 0xd9, 0xe5, 0xcc, 0xb5, 0x18, 0x17, 0x92, 0x75, 0xe9, 0xb4, 0x81, + 0x47, 0xd2, 0xcd, 0x28, 0x07, 0xd9, 0xcd, 0x6f, 0x0c, 0xf3, 0xca, 0x51}, + {0x0a, 0xe0, 0x74, 0x76, 0x42, 0xa7, 0x0b, 0xa6, 0xf3, 0x7b, 0x7a, 0xa1, 0x70, 0x85, + 0x0e, 0x63, 0xcc, 0x24, 0x33, 0xcf, 0x3d, 0x56, 0x58, 0x37, 0xaa, 0xfd, 0x83, 0x23, + 0x29, 0xaa, 0x04, 0x55, 0xc7, 0x54, 0xac, 0x18, 0x9a, 0xf9, 0x7a, 0x73, 0x0f, 0xb3, + 0x1c, 0xc5, 0xdc, 0x78, 0x33, 0x90, 0xc7, 0x0c, 0xe1, 0x4c, 0x33, 0xbc, 0x89, 0x2b, + 0x9a, 0xe9, 0xf8, 0x89, 0xc1, 0x29, 0xae, 0x12, 0xcf, 0x01, 0x0d, 0x1f, 0xcb, 0xc0, + 0x9e, 0xa9, 0xae, 0xf7, 0x34, 0x3a, 0xcc, 0xef, 0xd1, 0x0d, 0x22, 0x4e, 0x9c, 0xd0, + 0x21, 0x75, 0xca, 0x55, 0xea, 0xa5, 0xeb, 0x58, 0xe9, 0x4f, 0xd1, 0x5f}, + {0x2c, 0xab, 0x45, 0x28, 0xdf, 0x2d, 0xdc, 0xb5, 0x93, 0xe9, 0x7f, 0x0a, 0xb1, 0x91, + 0x94, 0x06, 0x46, 0xe3, 0x02, 0x40, 0xd6, 0xf3, 0xaa, 0x4d, 0xd1, 0x74, 0x64, 0x58, + 0x6e, 0xf2, 0x3f, 0x09, 0x8e, 0xcb, 0x93, 0xbf, 0x5e, 0xfe, 0x42, 0x3c, 0x5f, 0x56, + 0xd4, 0x36, 0x51, 0xa8, 0xdf, 0xbe, 0xe8, 0x20, 0x42, 0x88, 0x9e, 0x85, 0xf0, 0xe0, + 0x28, 0xd1, 0x25, 0x07, 0x96, 0x3f, 0xd7, 0x7d, 0x29, 0x98, 0x05, 0x68, 0xfe, 0x24, + 0x0d, 0xb1, 0xe5, 0x23, 0xaf, 0xdb, 0x72, 0x06, 0x73, 0x75, 0x29, 0xac, 0x57, 0xb4, + 0x3a, 0x25, 0x67, 0x13, 0xa4, 0x70, 0xb4, 0x86, 0xbc, 0xbc, 0x59, 0x2f}, + {0x5f, 0x13, 0x17, 0x99, 0x42, 0x7d, 0x84, 0x83, 0xd7, 0x03, 0x7d, 0x56, 0x1f, 0x91, + 0x1b, 0xad, 0xd1, 0xaa, 0x77, 0xbe, 0xd9, 0x48, 0x77, 0x7e, 0x4a, 0xaf, 0x51, 0x2e, + 0x2e, 0xb4, 0x58, 0x54, 0x01, 0xc3, 0x91, 0xb6, 0x60, 0xd5, 0x41, 0x70, 0x1e, 0xe7, + 0xd7, 0xad, 0x3f, 0x1b, 0x20, 0x85, 0x85, 0x55, 0x33, 0x11, 0x63, 0xe1, 0xc2, 0x16, + 0xb1, 0x28, 0x08, 0x01, 0x3d, 0x5e, 0xa5, 0x2a, 0x4f, 0x44, 0x07, 0x0c, 0xe6, 0x92, + 0x51, 0xed, 0x10, 0x1d, 0x42, 0x74, 0x2d, 0x4e, 0xc5, 0x42, 0x64, 0xc8, 0xb5, 0xfd, + 0x82, 0x4c, 0x2b, 0x35, 0x64, 0x86, 0x76, 0x8a, 0x4a, 0x00, 0xe9, 0x13}, + {0xdb, 0xce, 0x2f, 0x83, 0x45, 0x88, 0x9d, 0x73, 0x63, 0xf8, 0x6b, 0xae, 0xc9, 0xd6, + 0x38, 0xfa, 0xf7, 0xfe, 0x4f, 0xb7, 0xca, 0x0d, 0xbc, 0x32, 0x5e, 0xe4, 0xbc, 0x14, + 0x88, 0x7e, 0x93, 0x73, 0x7f, 0x87, 0x3b, 0x19, 0xc9, 0x00, 0x2e, 0xbb, 0x6b, 0x50, + 0xdc, 0xe0, 0x90, 0xa8, 0xe3, 0xec, 0x9f, 0x64, 0xde, 0x36, 0xc0, 0xb7, 0xf3, 0xec, + 0x1a, 0x9e, 0xde, 0x98, 0x08, 0x04, 0x46, 0x5f, 0x8d, 0xf4, 0x7b, 0x29, 0x16, 0x71, + 0x03, 0xb9, 0x34, 0x68, 0xf0, 0xd4, 0x22, 0x3b, 0xd1, 0xa9, 0xc6, 0xbd, 0x96, 0x46, + 0x57, 0x15, 0x97, 0xe1, 0x35, 0xe8, 0xd5, 0x91, 0xe8, 0xa4, 0xf8, 0x2c}, + {0x67, 0x0f, 0x11, 0x07, 0x87, 0xfd, 0x93, 0x6d, 0x49, 0xb5, 0x38, 0x7c, 0xd3, 0x09, + 0x4c, 0xdd, 0x86, 0x6a, 0x73, 0xc2, 0x4c, 0x6a, 0xb1, 0x7c, 0x09, 0x2a, 0x25, 0x58, + 0x6e, 0xbd, 0x49, 0x20, 0xa2, 0x6b, 0xd0, 0x17, 0x7e, 0x48, 0xb5, 0x2c, 0x6b, 0x19, + 0x50, 0x39, 0x1c, 0x38, 0xd2, 0x24, 0x30, 0x8a, 0x97, 0x85, 0x81, 0x9c, 0x65, 0xd7, + 0xf6, 0xa4, 0xd6, 0x91, 0x28, 0x7f, 0x6f, 0x7a, 0x49, 0xef, 0x9a, 0x6a, 0x8d, 0xfd, + 0x09, 0x7d, 0x0b, 0xb9, 0x3d, 0x5b, 0xbe, 0x60, 0xee, 0xf0, 0xd4, 0xbf, 0x9e, 0x51, + 0x2c, 0xb5, 0x21, 0x4c, 0x1d, 0x94, 0x45, 0xc5, 0xdf, 0xaa, 0x11, 0x60}, + {0x3c, 0xf8, 0x95, 0xcf, 0x6d, 0x92, 0x67, 0x5f, 0x71, 0x90, 0x28, 0x71, 0x61, 0x85, + 0x7e, 0x7c, 0x5b, 0x7a, 0x8f, 0x99, 0xf3, 0xe7, 0xa1, 0xd6, 0xe0, 0xf9, 0x62, 0x0b, + 0x1b, 0xcc, 0xc5, 0x6f, 0x90, 0xf8, 0xcb, 0x02, 0xc8, 0xd0, 0xde, 0x63, 0xaa, 0x6a, + 0xff, 0x0d, 0xca, 0x98, 0xd0, 0xfb, 0x99, 0xed, 0xb6, 0xb9, 0xfd, 0x0a, 0x4d, 0x62, + 0x1e, 0x0b, 0x34, 0x79, 0xb7, 0x18, 0xce, 0x69, 0xcb, 0x79, 0x98, 0xb2, 0x28, 0x55, + 0xef, 0xd1, 0x92, 0x90, 0x7e, 0xd4, 0x3c, 0xae, 0x1a, 0xdd, 0x52, 0x23, 0x9f, 0x18, + 0x42, 0x04, 0x7e, 0x12, 0xf1, 0x01, 0x71, 0xe5, 0x3a, 0x6b, 0x59, 0x15}, + {0xa2, 0x79, 0x91, 0x3f, 0xd2, 0x39, 0x27, 0x46, 0xcf, 0xdd, 0xd6, 0x97, 0x31, 0x12, + 0x83, 0xff, 0x8a, 0x14, 0xf2, 0x53, 0xb5, 0xde, 0x07, 0x13, 0xda, 0x4d, 0x5f, 0x7b, + 0x68, 0x37, 0x22, 0x0d, 0xca, 0x24, 0x51, 0x7e, 0x16, 0x31, 0xff, 0x09, 0xdf, 0x45, + 0xc7, 0xd9, 0x8b, 0x15, 0xe4, 0x0b, 0xe5, 0x56, 0xf5, 0x7e, 0x22, 0x7d, 0x2b, 0x29, + 0x38, 0xd1, 0xb6, 0xaf, 0x41, 0xe2, 0xa4, 0x3a, 0xf5, 0x05, 0x33, 0x2a, 0xbf, 0x38, + 0xc1, 0x2c, 0xc3, 0x26, 0xe9, 0xa2, 0x8f, 0x3f, 0x58, 0x48, 0xeb, 0xd2, 0x49, 0x55, + 0xa2, 0xb1, 0x3a, 0x08, 0x6c, 0xa3, 0x87, 0x46, 0x6e, 0xaa, 0xfc, 0x32}, + {0xf5, 0x9a, 0x7d, 0xc5, 0x8d, 0x6e, 0xc5, 0x7b, 0xf2, 0xbd, 0xf0, 0x9d, 0xed, 0xd2, + 0x0b, 0x3e, 0xa3, 0xe4, 0xef, 0x22, 0xde, 0x14, 0xc0, 0xaa, 0x5c, 0x6a, 0xbd, 0xfe, + 0xce, 0xe9, 0x27, 0x46, 0xdf, 0xcc, 0x87, 0x27, 0x73, 0xa4, 0x07, 0x32, 0xf8, 0xe3, + 0x13, 0xf2, 0x08, 0x19, 0xe3, 0x17, 0x4e, 0x96, 0x0d, 0xf6, 0xd7, 0xec, 0xb2, 0xd5, + 0xe9, 0x0b, 0x60, 0xc2, 0x36, 0x63, 0x6f, 0x74, 0x1c, 0x97, 0x6c, 0xab, 0x45, 0xf3, + 0x4a, 0x3f, 0x1f, 0x73, 0x43, 0x99, 0x72, 0xeb, 0x88, 0xe2, 0x6d, 0x18, 0x44, 0x03, + 0x8a, 0x6a, 0x59, 0x33, 0x93, 0x62, 0xd6, 0x7e, 0x00, 0x17, 0x49, 0x7b}, + {0x64, 0xb0, 0x84, 0xab, 0x5c, 0xfb, 0x85, 0x2d, 0x14, 0xbc, 0xf3, 0x89, 0xd2, 0x10, + 0x78, 0x49, 0x0c, 0xce, 0x15, 0x7b, 0x44, 0xdc, 0x6a, 0x47, 0x7b, 0xfd, 0x44, 0xf8, + 0x76, 0xa3, 0x2b, 0x12, 0xdd, 0xa2, 0x53, 0xdd, 0x28, 0x1b, 0x34, 0x54, 0x3f, 0xfc, + 0x42, 0xdf, 0x5b, 0x90, 0x17, 0xaa, 0xf4, 0xf8, 0xd2, 0x4d, 0xd9, 0x92, 0xf5, 0x0f, + 0x7d, 0xd3, 0x8c, 0xe0, 0x0f, 0x62, 0x03, 0x1d, 0x54, 0xe5, 0xb4, 0xa2, 0xcd, 0x32, + 0x02, 0xc2, 0x7f, 0x18, 0x5d, 0x11, 0x42, 0xfd, 0xd0, 0x9e, 0xd9, 0x79, 0xd4, 0x7d, + 0xbe, 0xb4, 0xab, 0x2e, 0x4c, 0xec, 0x68, 0x2b, 0xf5, 0x0b, 0xc7, 0x02}, + {0xbb, 0x2f, 0x0b, 0x5d, 0x4b, 0xec, 0x87, 0xa2, 0xca, 0x82, 0x48, 0x07, 0x90, 0x57, + 0x5c, 0x41, 0x5c, 0x81, 0xd0, 0xc1, 0x1e, 0xa6, 0x44, 0xe0, 0xe0, 0xf5, 0x9e, 0x40, + 0x0a, 0x4f, 0x33, 0x26, 0xe1, 0x72, 0x8d, 0x45, 0xbf, 0x32, 0xe5, 0xac, 0xb5, 0x3c, + 0xb7, 0x7c, 0xe0, 0x68, 0xe7, 0x5b, 0xe7, 0xbd, 0x8b, 0xee, 0x94, 0x7d, 0xcf, 0x56, + 0x03, 0x3a, 0xb4, 0xfe, 0xe3, 0x97, 0x06, 0x6b, 0xc0, 0xa3, 0x62, 0xdf, 0x4a, 0xf0, + 0xc8, 0xb6, 0x5d, 0xa4, 0x6d, 0x07, 0xef, 0x00, 0xf0, 0x3e, 0xa9, 0xd2, 0xf0, 0x49, + 0x58, 0xb9, 0x9c, 0x9c, 0xae, 0x2f, 0x1b, 0x44, 0x43, 0x7f, 0xc3, 0x1c}, + {0x4f, 0x32, 0xc7, 0x5c, 0x5a, 0x56, 0x8f, 0x50, 0x22, 0xa9, 0x06, 0xe5, 0xc0, 0xc4, + 0x61, 0xd0, 0x19, 0xac, 0x45, 0x5c, 0xdb, 0xab, 0x18, 0xfb, 0x4a, 0x31, 0x80, 0x03, + 0xc1, 0x09, 0x68, 0x6c, 0xb9, 0xae, 0xce, 0xc9, 0xf1, 0x56, 0x66, 0xd7, 0x6a, 0x65, + 0xe5, 0x18, 0xf8, 0x15, 0x5b, 0x1c, 0x34, 0x23, 0x4c, 0x84, 0x32, 0x28, 0xe7, 0x26, + 0x38, 0x68, 0x19, 0x2f, 0x77, 0x6f, 0x34, 0x3a, 0xc8, 0x6a, 0xda, 0xe2, 0x12, 0x51, + 0xd5, 0xd2, 0xed, 0x51, 0xe8, 0xb1, 0x31, 0x03, 0xbd, 0xe9, 0x62, 0x72, 0xc6, 0x8e, + 0xdd, 0x46, 0x07, 0x96, 0xd0, 0xc5, 0xf7, 0x6e, 0x9f, 0x1b, 0x91, 0x05}, + {0xbb, 0x0e, 0xdf, 0xf5, 0x83, 0x99, 0x33, 0xc1, 0xac, 0x4c, 0x2c, 0x51, 0x8f, 0x75, + 0xf3, 0xc0, 0xe1, 0x98, 0xb3, 0x0b, 0x0a, 0x13, 0xf1, 0x2c, 0x62, 0x0c, 0x27, 0xaa, + 0xf9, 0xec, 0x3c, 0x6b, 0xef, 0xea, 0x2e, 0x51, 0xf3, 0xac, 0x49, 0x53, 0x49, 0xcb, + 0xc1, 0x1c, 0xd3, 0x41, 0xc1, 0x20, 0x8d, 0x68, 0x9a, 0xa9, 0x07, 0x0c, 0x18, 0x24, + 0x17, 0x2d, 0x4b, 0xc6, 0xd1, 0xf9, 0x5e, 0x55, 0x08, 0xbd, 0x73, 0x3b, 0xba, 0x70, + 0xa7, 0x36, 0x0c, 0xbf, 0xaf, 0xa3, 0x08, 0xef, 0x4a, 0x62, 0xf2, 0x46, 0x09, 0xb4, + 0x98, 0xff, 0x37, 0x57, 0x9d, 0x74, 0x81, 0x33, 0xe1, 0x4d, 0x5f, 0x67}, + {0xfc, 0x82, 0x17, 0x6b, 0x03, 0x52, 0x2c, 0x0e, 0xb4, 0x83, 0xad, 0x6c, 0x81, 0x6c, + 0x81, 0x64, 0x3e, 0x07, 0x64, 0x69, 0xd9, 0xbd, 0xdc, 0xd0, 0x20, 0xc5, 0x64, 0x01, + 0xf7, 0x9d, 0xd9, 0x13, 0x1d, 0xb3, 0xda, 0x3b, 0xd9, 0xf6, 0x2f, 0xa1, 0xfe, 0x2d, + 0x65, 0x9d, 0x0f, 0xd8, 0x25, 0x07, 0x87, 0x94, 0xbe, 0x9a, 0xf3, 0x4f, 0x9c, 0x01, + 0x43, 0x3c, 0xcd, 0x82, 0xb8, 0x50, 0xf4, 0x60, 0xca, 0xc0, 0xe5, 0x21, 0xc3, 0x5e, + 0x4b, 0x01, 0xa2, 0xbf, 0x19, 0xd7, 0xc9, 0x69, 0xcb, 0x4f, 0xa0, 0x23, 0x00, 0x75, + 0x18, 0x1c, 0x5f, 0x4e, 0x80, 0xac, 0xed, 0x55, 0x9e, 0xde, 0x06, 0x1c}, + {0xe2, 0xc4, 0x3e, 0xa3, 0xd6, 0x7a, 0x0f, 0x99, 0x8e, 0xe0, 0x2e, 0xbe, 0x38, 0xf9, + 0x08, 0x66, 0x15, 0x45, 0x28, 0x63, 0xc5, 0x43, 0xa1, 0x9c, 0x0d, 0xb6, 0x2d, 0xec, + 0x1f, 0x8a, 0xf3, 0x4c, 0xaa, 0x69, 0x6d, 0xff, 0x40, 0x2b, 0xd5, 0xff, 0xbb, 0x49, + 0x40, 0xdc, 0x18, 0x0b, 0x53, 0x34, 0x97, 0x98, 0x4d, 0xa3, 0x2f, 0x5c, 0x4a, 0x5e, + 0x2d, 0xba, 0x32, 0x7d, 0x8e, 0x6f, 0x09, 0x78, 0xe7, 0x5c, 0xfa, 0x0d, 0x65, 0xaa, + 0xaa, 0xa0, 0x8c, 0x47, 0xb5, 0x48, 0x2a, 0x9e, 0xc4, 0xf9, 0x5b, 0x72, 0x03, 0x70, + 0x7d, 0xcc, 0x09, 0x4f, 0xbe, 0x1a, 0x09, 0x26, 0x3a, 0xad, 0x3c, 0x37}, + {0x7c, 0xf5, 0xc9, 0x82, 0x4d, 0x63, 0x94, 0xb2, 0x36, 0x45, 0x93, 0x24, 0xe1, 0xfd, + 0xcb, 0x1f, 0x5a, 0xdb, 0x8c, 0x41, 0xb3, 0x4d, 0x9c, 0x9e, 0xfc, 0x19, 0x44, 0x45, + 0xd9, 0xf3, 0x40, 0x00, 0xad, 0xbb, 0xdd, 0x89, 0xfb, 0xa8, 0xbe, 0xf1, 0xcb, 0xae, + 0xae, 0x61, 0xbc, 0x2c, 0xcb, 0x3b, 0x9d, 0x8d, 0x9b, 0x1f, 0xbb, 0xa7, 0x58, 0x8f, + 0x86, 0xa6, 0x12, 0x51, 0xda, 0x7e, 0x54, 0x21, 0xd3, 0x86, 0x59, 0xfd, 0x39, 0xe9, + 0xfd, 0xde, 0x0c, 0x38, 0x0a, 0x51, 0x89, 0x2c, 0x27, 0xf4, 0xb9, 0x19, 0x31, 0xbb, + 0x07, 0xa4, 0x2b, 0xb7, 0xf4, 0x4d, 0x25, 0x4a, 0x33, 0x0a, 0x55, 0x63}, + {0x37, 0xcf, 0x69, 0xb5, 0xed, 0xd6, 0x07, 0x65, 0xe1, 0x2e, 0xa5, 0x0c, 0xb0, 0x29, + 0x84, 0x17, 0x5d, 0xd6, 0x6b, 0xeb, 0x90, 0x00, 0x7c, 0xea, 0x51, 0x8f, 0xf7, 0xda, + 0xc7, 0x62, 0xea, 0x3e, 0x49, 0x7b, 0x54, 0x72, 0x45, 0x58, 0xba, 0x9b, 0xe0, 0x08, + 0xc4, 0xe2, 0xfa, 0xc6, 0x05, 0xf3, 0x8d, 0xf1, 0x34, 0xc7, 0x69, 0xfa, 0xe8, 0x60, + 0x7a, 0x76, 0x7d, 0xaa, 0xaf, 0x2b, 0xa9, 0x39, 0x4e, 0x27, 0x93, 0xe6, 0x13, 0xc7, + 0x24, 0x9d, 0x75, 0xd3, 0xdb, 0x68, 0x77, 0x85, 0x63, 0x5f, 0x9a, 0xb3, 0x8a, 0xeb, + 0x60, 0x55, 0x52, 0x70, 0xcd, 0xc4, 0xc9, 0x65, 0x06, 0x6a, 0x43, 0x68}, + {0x27, 0x3f, 0x2f, 0x20, 0xe8, 0x35, 0x02, 0xbc, 0xb0, 0x75, 0xf9, 0x64, 0xe2, 0x00, + 0x5c, 0xc7, 0x16, 0x24, 0x8c, 0xa3, 0xd5, 0xe9, 0xa4, 0x91, 0xf9, 0x89, 0xb7, 0x8a, + 0xf6, 0xe7, 0xb6, 0x17, 0x7c, 0x10, 0x20, 0xe8, 0x17, 0xd3, 0x56, 0x1e, 0x65, 0xe9, + 0x0a, 0x84, 0x44, 0x68, 0x26, 0xc5, 0x7a, 0xfc, 0x0f, 0x32, 0xc6, 0xa1, 0xe0, 0xc1, + 0x72, 0x14, 0x61, 0x91, 0x9c, 0x66, 0x73, 0x53, 0x57, 0x52, 0x0e, 0x9a, 0xab, 0x14, + 0x28, 0x5d, 0xfc, 0xb3, 0xca, 0xc9, 0x84, 0x20, 0x8f, 0x90, 0xca, 0x1e, 0x2d, 0x5b, + 0x88, 0xf5, 0xca, 0xaf, 0x11, 0x7d, 0xf8, 0x78, 0xa6, 0xb5, 0xb4, 0x1c}, + {0x6c, 0xfc, 0x4a, 0x39, 0x6b, 0xc0, 0x64, 0xb6, 0xb1, 0x5f, 0xda, 0x98, 0x24, 0xde, + 0x88, 0x0c, 0x34, 0xd8, 0xca, 0x4b, 0x16, 0x03, 0x8d, 0x4f, 0xa2, 0x34, 0x74, 0xde, + 0x78, 0xca, 0x0b, 0x33, 0xe7, 0x07, 0xa0, 0xa2, 0x62, 0xaa, 0x74, 0x6b, 0xb1, 0xc7, + 0x71, 0xf0, 0xb0, 0xe0, 0x11, 0xf3, 0x23, 0xe2, 0x0b, 0x00, 0x38, 0xe4, 0x07, 0x57, + 0xac, 0x6e, 0xef, 0x82, 0x2d, 0xfd, 0xc0, 0x2d, 0x4e, 0x74, 0x19, 0x11, 0x84, 0xff, + 0x2e, 0x98, 0x24, 0x47, 0x07, 0x2b, 0x96, 0x5e, 0x69, 0xf9, 0xfb, 0x53, 0xc9, 0xbf, + 0x4f, 0xc1, 0x8a, 0xc5, 0xf5, 0x1c, 0x9f, 0x36, 0x1b, 0xbe, 0x31, 0x3c}, + {0xee, 0x8a, 0x94, 0x08, 0x4d, 0x86, 0xf4, 0xb0, 0x6f, 0x1c, 0xba, 0x91, 0xee, 0x19, + 0xdc, 0x07, 0x58, 0xa1, 0xac, 0xa6, 0xae, 0xcd, 0x75, 0x79, 0xbb, 0xd4, 0x62, 0x42, + 0x13, 0x61, 0x0b, 0x33, 0x72, 0x42, 0xcb, 0xf9, 0x93, 0xbc, 0x68, 0xc1, 0x98, 0xdb, + 0xce, 0xc7, 0x1f, 0x71, 0xb8, 0xae, 0x7a, 0x8d, 0xac, 0x34, 0xaa, 0x52, 0x0e, 0x7f, + 0xbb, 0x55, 0x7d, 0x7e, 0x09, 0xc1, 0xce, 0x41, 0x8a, 0x80, 0x6d, 0xa2, 0xd7, 0x19, + 0x96, 0xf7, 0x6d, 0x15, 0x9e, 0x1d, 0x9e, 0xd4, 0x1f, 0xbb, 0x27, 0xdf, 0xa1, 0xdb, + 0x6c, 0xc3, 0xd7, 0x73, 0x7d, 0x77, 0x28, 0x1f, 0xd9, 0x4c, 0xb4, 0x26}, + {0x75, 0x74, 0x38, 0x8f, 0x47, 0x48, 0xf0, 0x51, 0x3c, 0xcb, 0xbe, 0x9c, 0xf4, 0xbc, + 0x5d, 0xb2, 0x55, 0x20, 0x9f, 0xd9, 0x44, 0x12, 0xab, 0x9a, 0xd6, 0xa5, 0x10, 0x1c, + 0x6c, 0x9e, 0x70, 0x2c, 0x83, 0x03, 0x73, 0x62, 0x93, 0xf2, 0xb7, 0xe1, 0x2c, 0x8a, + 0xca, 0xeb, 0xff, 0x79, 0x52, 0x4b, 0x14, 0x13, 0xd4, 0xbf, 0x8a, 0x77, 0xfc, 0xda, + 0x0f, 0x61, 0x72, 0x9c, 0x14, 0x10, 0xeb, 0x7d, 0x7a, 0xee, 0x66, 0x87, 0x6a, 0xaf, + 0x62, 0xcb, 0x0e, 0xcd, 0x53, 0x55, 0x04, 0xec, 0xcb, 0x66, 0xb5, 0xe4, 0x0b, 0x0f, + 0x38, 0x01, 0x80, 0x58, 0xea, 0xe2, 0x2c, 0xf6, 0x9f, 0x8e, 0xe6, 0x08}, + {0xad, 0x30, 0xc1, 0x4b, 0x0a, 0x50, 0xad, 0x34, 0x9c, 0xd4, 0x0b, 0x3d, 0x49, 0xdb, + 0x38, 0x8d, 0xbe, 0x89, 0x0a, 0x50, 0x98, 0x3d, 0x5c, 0xa2, 0x09, 0x3b, 0xba, 0xee, + 0x87, 0x3f, 0x1f, 0x2f, 0xf9, 0xf2, 0xb8, 0x0a, 0xd5, 0x09, 0x2d, 0x2f, 0xdf, 0x23, + 0x59, 0xc5, 0x8d, 0x21, 0xb9, 0xac, 0xb9, 0x6c, 0x76, 0x73, 0x26, 0x34, 0x8f, 0x4a, + 0xf5, 0x19, 0xf7, 0x38, 0xd7, 0x3b, 0xb1, 0x4c, 0x4a, 0xb6, 0x15, 0xe5, 0x75, 0x8c, + 0x84, 0xf7, 0x38, 0x90, 0x4a, 0xdb, 0xba, 0x01, 0x95, 0xa5, 0x50, 0x1b, 0x75, 0x3f, + 0x3f, 0x31, 0x0d, 0xc2, 0xe8, 0x2e, 0xae, 0xc0, 0x53, 0xe3, 0xa1, 0x19}, + {0xc3, 0x05, 0xfa, 0xba, 0x60, 0x75, 0x1c, 0x7d, 0x61, 0x5e, 0xe5, 0xc6, 0xa0, 0xa0, + 0xe1, 0xb3, 0x73, 0x64, 0xd6, 0xc0, 0x18, 0x97, 0x52, 0xe3, 0x86, 0x34, 0x0c, 0xc2, + 0x11, 0x6b, 0x54, 0x41, 0xbd, 0xbd, 0x96, 0xd5, 0xcd, 0x72, 0x21, 0xb4, 0x40, 0xfc, + 0xee, 0x98, 0x43, 0x45, 0xe0, 0x93, 0xb5, 0x09, 0x41, 0xb4, 0x47, 0x53, 0xb1, 0x9f, + 0x34, 0xae, 0x66, 0x02, 0x99, 0xd3, 0x6b, 0x73, 0xb4, 0xb3, 0x34, 0x93, 0x50, 0x2d, + 0x53, 0x85, 0x73, 0x65, 0x81, 0x60, 0x4b, 0x11, 0xfd, 0x46, 0x75, 0x83, 0x5c, 0x42, + 0x30, 0x5f, 0x5f, 0xcc, 0x5c, 0xab, 0x7f, 0xb8, 0xa2, 0x95, 0x22, 0x41}, + {0xe9, 0xd6, 0x7e, 0xf5, 0x88, 0x9b, 0xc9, 0x19, 0x25, 0xc8, 0xf8, 0x6d, 0x26, 0xcb, + 0x93, 0x53, 0x73, 0xd2, 0x0a, 0xb3, 0x13, 0x32, 0xee, 0x5c, 0x34, 0x2e, 0x2d, 0xb5, + 0xeb, 0x53, 0xe1, 0x14, 0xc6, 0xea, 0x93, 0xe2, 0x61, 0x52, 0x65, 0x2e, 0xdb, 0xac, + 0x33, 0x21, 0x03, 0x92, 0x5a, 0x84, 0x6b, 0x99, 0x00, 0x79, 0xcb, 0x75, 0x09, 0x46, + 0x80, 0xdd, 0x5a, 0x19, 0x8d, 0xbb, 0x60, 0x07, 0x8a, 0x81, 0xe6, 0xcd, 0x17, 0x1a, + 0x3e, 0x41, 0x84, 0xa0, 0x69, 0xed, 0xa9, 0x6d, 0x15, 0x57, 0xb1, 0xcc, 0xca, 0x46, + 0x8f, 0x26, 0xbf, 0x2c, 0xf2, 0xc5, 0x3a, 0xc3, 0x9b, 0xbe, 0x34, 0x6b}, + {0xb2, 0xc0, 0x78, 0x3a, 0x64, 0x2f, 0xdf, 0xf3, 0x7c, 0x02, 0x2e, 0xf2, 0x1e, 0x97, + 0x3e, 0x4c, 0xa3, 0xb5, 0xc1, 0x49, 0x5e, 0x1c, 0x7d, 0xec, 0x2d, 0xdd, 0x22, 0x09, + 0x8f, 0xc1, 0x12, 0x20, 0xd3, 0xf2, 0x71, 0x65, 0x65, 0x69, 0xfc, 0x11, 0x7a, 0x73, + 0x0e, 0x53, 0x45, 0xe8, 0xc9, 0xc6, 0x35, 0x50, 0xfe, 0xd4, 0xa2, 0xe7, 0x3a, 0xe3, + 0x0b, 0xd3, 0x6d, 0x2e, 0xb6, 0xc7, 0xb9, 0x01, 0x29, 0x9d, 0xc8, 0x5a, 0xe5, 0x55, + 0x0b, 0x88, 0x63, 0xa7, 0xa0, 0x45, 0x1f, 0x24, 0x83, 0x14, 0x1f, 0x6c, 0xe7, 0xc2, + 0xdf, 0xef, 0x36, 0x3d, 0xe8, 0xad, 0x4b, 0x4e, 0x78, 0x5b, 0xaf, 0x08}, + {0x33, 0x25, 0x1f, 0x88, 0xdc, 0x99, 0x34, 0x28, 0xb6, 0x23, 0x93, 0x77, 0xda, 0x25, + 0x05, 0x9d, 0xf4, 0x41, 0x34, 0x67, 0xfb, 0xdd, 0x7a, 0x89, 0x8d, 0x16, 0x3a, 0x16, + 0x71, 0x9d, 0xb7, 0x32, 0x4b, 0x2c, 0xcc, 0x89, 0xd2, 0x14, 0x73, 0xe2, 0x8d, 0x17, + 0x87, 0xa2, 0x11, 0xbd, 0xe4, 0x4b, 0xce, 0x64, 0x33, 0xfa, 0xd6, 0x28, 0xd5, 0x18, + 0x6e, 0x82, 0xd9, 0xaf, 0xd5, 0xc1, 0x23, 0x64, 0x6a, 0xb3, 0xfc, 0xed, 0xd9, 0xf8, + 0x85, 0xcc, 0xf9, 0xe5, 0x46, 0x37, 0x8f, 0xc2, 0xbc, 0x22, 0xcd, 0xd3, 0xe5, 0xf9, + 0x38, 0xe3, 0x9d, 0xe4, 0xcc, 0x2d, 0x3e, 0xc1, 0xfb, 0x5e, 0x0a, 0x48}, + {0x71, 0x20, 0x62, 0x01, 0x0b, 0xe7, 0x51, 0x0b, 0xc5, 0xaf, 0x1d, 0x8b, 0xcf, 0x05, + 0xb5, 0x06, 0xcd, 0xab, 0x5a, 0xef, 0x61, 0xb0, 0x6b, 0x2c, 0x31, 0xbf, 0xb7, 0x0c, + 0x60, 0x27, 0xaa, 0x47, 0x1f, 0x22, 0xce, 0x42, 0xe4, 0x4c, 0x61, 0xb6, 0x28, 0x39, + 0x05, 0x4c, 0xcc, 0x9d, 0x19, 0x6e, 0x03, 0xbe, 0x1c, 0xdc, 0xa4, 0xb4, 0x3f, 0x66, + 0x06, 0x8e, 0x1c, 0x69, 0x47, 0x1d, 0xb3, 0x24, 0xc3, 0xf8, 0x15, 0xc0, 0xed, 0x1e, + 0x54, 0x2a, 0x7c, 0x3f, 0x69, 0x7c, 0x7e, 0xfe, 0xa4, 0x11, 0xd6, 0x78, 0xa2, 0x4e, + 0x13, 0x66, 0xaf, 0xf0, 0x94, 0xa0, 0xdd, 0x14, 0x5d, 0x58, 0x5b, 0x54}, + {0x0f, 0x3a, 0xd4, 0xa0, 0x5e, 0x27, 0xbf, 0x67, 0xbe, 0xee, 0x9b, 0x08, 0x34, 0x8e, + 0xe6, 0xad, 0x2e, 0xe7, 0x79, 0xd4, 0x4c, 0x13, 0x89, 0x42, 0x54, 0x54, 0xba, 0x32, + 0xc3, 0xf9, 0x62, 0x0f, 0xe1, 0x21, 0xb3, 0xe3, 0xd0, 0xe4, 0x04, 0x62, 0x95, 0x1e, + 0xff, 0x28, 0x7a, 0x63, 0xaa, 0x3b, 0x9e, 0xbd, 0x99, 0x5b, 0xfd, 0xcf, 0x0c, 0x0b, + 0x71, 0xd0, 0xc8, 0x64, 0x3e, 0xdc, 0x22, 0x4d, 0x39, 0x5f, 0x3b, 0xd6, 0x89, 0x65, + 0xb4, 0xfc, 0x61, 0xcf, 0xcb, 0x57, 0x3f, 0x6a, 0xae, 0x5c, 0x05, 0xfa, 0x3a, 0x95, + 0xd2, 0xc2, 0xba, 0xfe, 0x36, 0x14, 0x37, 0x36, 0x1a, 0xa0, 0x0f, 0x1c}, + {0xff, 0x3d, 0x94, 0x22, 0xb6, 0x04, 0xc6, 0xd2, 0xa0, 0xb3, 0xcf, 0x44, 0xce, 0xbe, + 0x8c, 0xbc, 0x78, 0x86, 0x80, 0x97, 0xf3, 0x4f, 0x25, 0x5d, 0xbf, 0xa6, 0x1c, 0x3b, + 0x4f, 0x61, 0xa3, 0x0f, 0x50, 0x6a, 0x93, 0x8c, 0x0e, 0x2b, 0x08, 0x69, 0xb6, 0xc5, + 0xda, 0xc1, 0x35, 0xa0, 0xc9, 0xf9, 0x34, 0xb6, 0xdf, 0xc4, 0x54, 0x3e, 0xb7, 0x6f, + 0x40, 0xc1, 0x2b, 0x1d, 0x9b, 0x41, 0x05, 0x40, 0xf0, 0x82, 0xbe, 0xb9, 0xbd, 0xfe, + 0x03, 0xa0, 0x90, 0xac, 0x44, 0x3a, 0xaf, 0xc1, 0x89, 0x20, 0x8e, 0xfa, 0x54, 0x19, + 0x91, 0x9f, 0x49, 0xf8, 0x42, 0xab, 0x40, 0xef, 0x8a, 0x21, 0xba, 0x1f}, + {0x3e, 0xf5, 0xc8, 0xfa, 0x48, 0x94, 0x54, 0xab, 0x41, 0x37, 0xa6, 0x7b, 0x9a, 0xe8, + 0xf6, 0x81, 0x01, 0x5e, 0x2b, 0x6c, 0x7d, 0x6c, 0xfd, 0x74, 0x42, 0x6e, 0xc8, 0xa8, + 0xca, 0x3a, 0x2e, 0x39, 0x94, 0x01, 0x7b, 0x3e, 0x04, 0x57, 0x3e, 0x4f, 0x7f, 0xaf, + 0xda, 0x08, 0xee, 0x3e, 0x1d, 0xa8, 0xf1, 0xde, 0xdc, 0x99, 0xab, 0xc6, 0x39, 0xc8, + 0xd5, 0x61, 0x77, 0xff, 0x13, 0x5d, 0x53, 0x6c, 0xaf, 0x35, 0x8a, 0x3e, 0xe9, 0x34, + 0xbd, 0x4c, 0x16, 0xe8, 0x87, 0x58, 0x44, 0x81, 0x07, 0x2e, 0xab, 0xb0, 0x9a, 0xf2, + 0x76, 0x9c, 0x31, 0x19, 0x3b, 0xc1, 0x0a, 0xd5, 0xe4, 0x7f, 0xe1, 0x25}, + {0x76, 0xf6, 0x04, 0x1e, 0xd7, 0x9b, 0x28, 0x0a, 0x95, 0x0f, 0x42, 0xd6, 0x52, 0x1c, + 0x8e, 0x20, 0xab, 0x1f, 0x69, 0x34, 0xb0, 0xd8, 0x86, 0x51, 0x51, 0xb3, 0x9f, 0x2a, + 0x44, 0x51, 0x57, 0x25, 0xa7, 0x21, 0xf1, 0x76, 0xf5, 0x7f, 0x5f, 0x91, 0xe3, 0x87, + 0xcd, 0x2f, 0x27, 0x32, 0x4a, 0xc3, 0x26, 0xe5, 0x1b, 0x4d, 0xde, 0x2f, 0xba, 0xcc, + 0x9b, 0x89, 0x69, 0x89, 0x8f, 0x82, 0xba, 0x6b, 0x01, 0x39, 0xfe, 0x90, 0x66, 0xbc, + 0xd1, 0xe2, 0xd5, 0x7a, 0x99, 0xa0, 0x18, 0x4a, 0xb5, 0x4c, 0xd4, 0x60, 0x84, 0xaf, + 0x14, 0x69, 0x1d, 0x97, 0xe4, 0x7b, 0x6b, 0x7f, 0x4f, 0x50, 0x9d, 0x55}, + {0xd5, 0x54, 0xeb, 0xb3, 0x78, 0x83, 0x73, 0xa7, 0x7c, 0x3c, 0x55, 0xa5, 0x66, 0xd3, + 0x69, 0x1d, 0xba, 0x00, 0x28, 0xf9, 0x62, 0xcf, 0x26, 0x0a, 0x17, 0x32, 0x7e, 0x80, + 0xd5, 0x12, 0xab, 0x01, 0xfd, 0x66, 0xd2, 0xf6, 0xe7, 0x91, 0x48, 0x9c, 0x1b, 0x78, + 0x07, 0x03, 0x9b, 0xa1, 0x44, 0x07, 0x3b, 0xe2, 0x61, 0x60, 0x1d, 0x8f, 0x38, 0x88, + 0x0e, 0xd5, 0x4b, 0x35, 0xa3, 0xa6, 0x3e, 0x12, 0x96, 0x2d, 0xe3, 0x41, 0x90, 0x18, + 0x8d, 0x11, 0x48, 0x58, 0x31, 0xd8, 0xc2, 0xe3, 0xed, 0xb9, 0xd9, 0x45, 0x32, 0xd8, + 0x71, 0x42, 0xab, 0x1e, 0x54, 0xa1, 0x18, 0xc9, 0xe2, 0x61, 0x39, 0x4a}, + {0xa0, 0xbb, 0xe6, 0xf8, 0xe0, 0x3b, 0xdc, 0x71, 0x0a, 0xe3, 0xff, 0x7e, 0x34, 0xf8, + 0xce, 0xd6, 0x6a, 0x47, 0x3a, 0xe1, 0x5f, 0x42, 0x92, 0xa9, 0x63, 0xb7, 0x1d, 0xfb, + 0xe3, 0xbc, 0xd6, 0x2c, 0x1e, 0x3f, 0x23, 0xf3, 0x44, 0xd6, 0x27, 0x03, 0x16, 0xf0, + 0xfc, 0x34, 0x0e, 0x26, 0x9a, 0x49, 0x79, 0xb9, 0xda, 0xf2, 0x16, 0xa7, 0xb5, 0x83, + 0x1f, 0x11, 0xd4, 0x9b, 0xad, 0xee, 0xac, 0x68, 0x10, 0xc2, 0xd7, 0xf3, 0x0e, 0xc9, + 0xb4, 0x38, 0x0c, 0x04, 0xad, 0xb7, 0x24, 0x6e, 0x8e, 0x30, 0x23, 0x3e, 0xe7, 0xb7, + 0xf1, 0xd9, 0x60, 0x38, 0x97, 0xf5, 0x08, 0xb5, 0xd5, 0x60, 0x57, 0x59}, + {0x97, 0x63, 0xaa, 0x04, 0xe1, 0xbf, 0x29, 0x61, 0xcb, 0xfc, 0xa7, 0xa4, 0x08, 0x00, + 0x96, 0x8f, 0x58, 0x94, 0x90, 0x7d, 0x89, 0xc0, 0x8b, 0x3f, 0xa9, 0x91, 0xb2, 0xdc, + 0x3e, 0xa4, 0x9f, 0x70, 0x90, 0x27, 0x02, 0xfd, 0xeb, 0xcb, 0x2a, 0x88, 0x60, 0x57, + 0x11, 0xc4, 0x05, 0x33, 0xaf, 0x89, 0xf4, 0x73, 0x34, 0x7d, 0xe3, 0x92, 0xf4, 0x65, + 0x2b, 0x5a, 0x51, 0x54, 0xdf, 0xc5, 0xb2, 0x2c, 0xca, 0x2a, 0xfd, 0x63, 0x8c, 0x5d, + 0x0a, 0xeb, 0xff, 0x4e, 0x69, 0x2e, 0x66, 0xc1, 0x2b, 0xd2, 0x3a, 0xb0, 0xcb, 0xf8, + 0x6e, 0xf3, 0x23, 0x27, 0x1f, 0x13, 0xc8, 0xf0, 0xec, 0x29, 0xf0, 0x70}, + {0x33, 0x3e, 0xed, 0x2e, 0xb3, 0x07, 0x13, 0x46, 0xe7, 0x81, 0x55, 0xa4, 0x33, 0x2f, + 0x04, 0xae, 0x66, 0x03, 0x5f, 0x19, 0xd3, 0x49, 0x44, 0xc9, 0x58, 0x48, 0x31, 0x6c, + 0x8a, 0x5d, 0x7d, 0x0b, 0xb9, 0xb0, 0x10, 0x5e, 0xaa, 0xaf, 0x6a, 0x2a, 0xa9, 0x1a, + 0x04, 0xef, 0x70, 0xa3, 0xf0, 0x78, 0x1f, 0xd6, 0x3a, 0xaa, 0x77, 0xfb, 0x3e, 0x77, + 0xe1, 0xd9, 0x4b, 0xa7, 0xa2, 0xa5, 0xec, 0x44, 0x43, 0xd5, 0x95, 0x7b, 0x32, 0x48, + 0xd4, 0x25, 0x1d, 0x0f, 0x34, 0xa3, 0x00, 0x83, 0xd3, 0x70, 0x2b, 0xc5, 0xe1, 0x60, + 0x1c, 0x53, 0x1c, 0xde, 0xe4, 0xe9, 0x7d, 0x2c, 0x51, 0x24, 0x22, 0x27}, + {0x2e, 0x34, 0xc5, 0x49, 0xaf, 0x92, 0xbc, 0x1a, 0xd0, 0xfa, 0xe6, 0xb2, 0x11, 0xd8, + 0xee, 0xff, 0x29, 0x4e, 0xc8, 0xfc, 0x8d, 0x8c, 0xa2, 0xef, 0x43, 0xc5, 0x4c, 0xa4, + 0x18, 0xdf, 0xb5, 0x11, 0xfc, 0x75, 0xa9, 0x42, 0x8a, 0xbb, 0x7b, 0xbf, 0x58, 0xa3, + 0xad, 0x96, 0x77, 0x39, 0x5c, 0x8c, 0x48, 0xaa, 0xed, 0xcd, 0x6f, 0xc7, 0x7f, 0xe2, + 0xa6, 0x20, 0xbc, 0xf6, 0xd7, 0x5f, 0x73, 0x19, 0x66, 0x42, 0xc8, 0x42, 0xd0, 0x90, + 0xab, 0xe3, 0x7e, 0x54, 0x19, 0x7f, 0x0f, 0x8e, 0x84, 0xeb, 0xb9, 0x97, 0xa4, 0x65, + 0xd0, 0xa1, 0x03, 0x25, 0x5f, 0x89, 0xdf, 0x91, 0x11, 0x91, 0xef, 0x0f}}; diff --git a/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_donna_basepoint_table.h b/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_donna_basepoint_table.h new file mode 100644 index 000000000..9c0cdfc0c --- /dev/null +++ b/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_donna_basepoint_table.h @@ -0,0 +1,2 @@ +/* multiples of the base point in packed {ysubx, xaddy, t2d} form */ +extern const uint8_t ALIGN(16) ge25519_niels_base_multiples[256][96]; diff --git a/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_donna_impl_base.c b/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_donna_impl_base.c new file mode 100644 index 000000000..778f24578 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_donna_impl_base.c @@ -0,0 +1,829 @@ +#include +#include "ed25519_donna.h" +#include "../memzero.h" + +/* sqrt(x) is such an integer y that 0 <= y <= p - 1, y % 2 = 0, and y^2 = x (mod p). */ +/* d = -121665 / 121666 */ +#if !defined(NDEBUG) +static const bignum25519 ALIGN(16) fe_d = { + 0x35978a3, + 0x0d37284, + 0x3156ebd, + 0x06a0a0e, + 0x001c029, + 0x179e898, + 0x3a03cbb, + 0x1ce7198, + 0x2e2b6ff, + 0x1480db3}; /* d */ +#endif +static const bignum25519 ALIGN(16) fe_sqrtm1 = { + 0x20ea0b0, + 0x186c9d2, + 0x08f189d, + 0x035697f, + 0x0bd0c60, + 0x1fbd7a7, + 0x2804c9e, + 0x1e16569, + 0x004fc1d, + 0x0ae0c92}; /* sqrt(-1) */ +//static const bignum25519 ALIGN(16) fe_d2 = { +// 0x2b2f159, 0x1a6e509, 0x22add7a, 0x0d4141d, 0x0038052, 0x0f3d130, 0x3407977, 0x19ce331, 0x1c56dff, 0x0901b67}; /* 2 * d */ + +/* A = 2 * (1 - d) / (1 + d) = 486662 */ +static const bignum25519 ALIGN(16) fe_ma2 = { + 0x33de3c9, + 0x1fff236, + 0x3ffffff, + 0x1ffffff, + 0x3ffffff, + 0x1ffffff, + 0x3ffffff, + 0x1ffffff, + 0x3ffffff, + 0x1ffffff}; /* -A^2 */ +static const bignum25519 ALIGN(16) fe_ma = { + 0x3f892e7, + 0x1ffffff, + 0x3ffffff, + 0x1ffffff, + 0x3ffffff, + 0x1ffffff, + 0x3ffffff, + 0x1ffffff, + 0x3ffffff, + 0x1ffffff}; /* -A */ +static const bignum25519 ALIGN(16) fe_fffb1 = { + 0x1e3bdff, + 0x025a2b3, + 0x18e5bab, + 0x0ba36ac, + 0x0b9afed, + 0x004e61c, + 0x31d645f, + 0x09d1bea, + 0x102529e, + 0x0063810}; /* sqrt(-2 * A * (A + 2)) */ +static const bignum25519 ALIGN(16) fe_fffb2 = { + 0x383650d, + 0x066df27, + 0x10405a4, + 0x1cfdd48, + 0x2b887f2, + 0x1e9a041, + 0x1d7241f, + 0x0612dc5, + 0x35fba5d, + 0x0cbe787}; /* sqrt(2 * A * (A + 2)) */ +static const bignum25519 ALIGN(16) fe_fffb3 = { + 0x0cfd387, + 0x1209e3a, + 0x3bad4fc, + 0x18ad34d, + 0x2ff6c02, + 0x0f25d12, + 0x15cdfe0, + 0x0e208ed, + 0x32eb3df, + 0x062d7bb}; /* sqrt(-sqrt(-1) * A * (A + 2)) */ +static const bignum25519 ALIGN(16) fe_fffb4 = { + 0x2b39186, + 0x14640ed, + 0x14930a7, + 0x04509fa, + 0x3b91bf0, + 0x0f7432e, + 0x07a443f, + 0x17f24d8, + 0x031067d, + 0x0690fcc}; /* sqrt(sqrt(-1) * A * (A + 2)) */ + +/* + Timing safe memory compare +*/ +int ed25519_verify(const unsigned char* x, const unsigned char* y, size_t len) { + size_t differentbits = 0; + while(len--) differentbits |= (*x++ ^ *y++); + return (int)(1 & ((differentbits - 1) >> 8)); +} + +/* + conversions +*/ + +void ge25519_p1p1_to_partial(ge25519* r, const ge25519_p1p1* p) { + curve25519_mul(r->x, p->x, p->t); + curve25519_mul(r->y, p->y, p->z); + curve25519_mul(r->z, p->z, p->t); +} + +void ge25519_p1p1_to_full(ge25519* r, const ge25519_p1p1* p) { + curve25519_mul(r->x, p->x, p->t); + curve25519_mul(r->y, p->y, p->z); + curve25519_mul(r->z, p->z, p->t); + curve25519_mul(r->t, p->x, p->y); +} + +void ge25519_full_to_pniels(ge25519_pniels* p, const ge25519* r) { + curve25519_sub(p->ysubx, r->y, r->x); + curve25519_add(p->xaddy, r->y, r->x); + curve25519_copy(p->z, r->z); + curve25519_mul(p->t2d, r->t, ge25519_ec2d); +} + +/* + adding & doubling +*/ + +void ge25519_double_p1p1(ge25519_p1p1* r, const ge25519* p) { + bignum25519 a = {0}, b = {0}, c = {0}; + + curve25519_square(a, p->x); + curve25519_square(b, p->y); + curve25519_square(c, p->z); + curve25519_add_reduce(c, c, c); + curve25519_add(r->x, p->x, p->y); + curve25519_square(r->x, r->x); + curve25519_add(r->y, b, a); + curve25519_sub(r->z, b, a); + curve25519_sub_after_basic(r->x, r->x, r->y); + curve25519_sub_after_basic(r->t, c, r->z); +} + +#ifndef ED25519_NO_PRECOMP +void ge25519_nielsadd2_p1p1( + ge25519_p1p1* r, + const ge25519* p, + const ge25519_niels* q, + unsigned char signbit) { + const bignum25519* qb = (const bignum25519*)q; + bignum25519* rb = (bignum25519*)r; + bignum25519 a = {0}, b = {0}, c = {0}; + + curve25519_sub(a, p->y, p->x); + curve25519_add(b, p->y, p->x); + curve25519_mul(a, a, qb[signbit]); /* x for +, y for - */ + curve25519_mul(r->x, b, qb[signbit ^ 1]); /* y for +, x for - */ + curve25519_add(r->y, r->x, a); + curve25519_sub(r->x, r->x, a); + curve25519_mul(c, p->t, q->t2d); + curve25519_add_reduce(r->t, p->z, p->z); + curve25519_copy(r->z, r->t); + curve25519_add(rb[2 + signbit], rb[2 + signbit], c); /* z for +, t for - */ + curve25519_sub(rb[2 + (signbit ^ 1)], rb[2 + (signbit ^ 1)], c); /* t for +, z for - */ +} +#endif + +void ge25519_pnielsadd_p1p1( + ge25519_p1p1* r, + const ge25519* p, + const ge25519_pniels* q, + unsigned char signbit) { + const bignum25519* qb = (const bignum25519*)q; + bignum25519* rb = (bignum25519*)r; + bignum25519 a = {0}, b = {0}, c = {0}; + + curve25519_sub(a, p->y, p->x); + curve25519_add(b, p->y, p->x); + curve25519_mul(a, a, qb[signbit]); /* ysubx for +, xaddy for - */ + curve25519_mul(r->x, b, qb[signbit ^ 1]); /* xaddy for +, ysubx for - */ + curve25519_add(r->y, r->x, a); + curve25519_sub(r->x, r->x, a); + curve25519_mul(c, p->t, q->t2d); + curve25519_mul(r->t, p->z, q->z); + curve25519_add_reduce(r->t, r->t, r->t); + curve25519_copy(r->z, r->t); + curve25519_add(rb[2 + signbit], rb[2 + signbit], c); /* z for +, t for - */ + curve25519_sub(rb[2 + (signbit ^ 1)], rb[2 + (signbit ^ 1)], c); /* t for +, z for - */ +} + +void ge25519_double_partial(ge25519* r, const ge25519* p) { + ge25519_p1p1 t = {0}; + ge25519_double_p1p1(&t, p); + ge25519_p1p1_to_partial(r, &t); +} + +void ge25519_double(ge25519* r, const ge25519* p) { + ge25519_p1p1 t = {0}; + ge25519_double_p1p1(&t, p); + ge25519_p1p1_to_full(r, &t); +} + +void ge25519_nielsadd2(ge25519* r, const ge25519_niels* q) { + bignum25519 a = {0}, b = {0}, c = {0}, e = {0}, f = {0}, g = {0}, h = {0}; + + curve25519_sub(a, r->y, r->x); + curve25519_add(b, r->y, r->x); + curve25519_mul(a, a, q->ysubx); + curve25519_mul(e, b, q->xaddy); + curve25519_add(h, e, a); + curve25519_sub(e, e, a); + curve25519_mul(c, r->t, q->t2d); + curve25519_add(f, r->z, r->z); + curve25519_add_after_basic(g, f, c); + curve25519_sub_after_basic(f, f, c); + curve25519_mul(r->x, e, f); + curve25519_mul(r->y, h, g); + curve25519_mul(r->z, g, f); + curve25519_mul(r->t, e, h); +} + +void ge25519_pnielsadd(ge25519_pniels* r, const ge25519* p, const ge25519_pniels* q) { + bignum25519 a = {0}, b = {0}, c = {0}, x = {0}, y = {0}, z = {0}, t = {0}; + + curve25519_sub(a, p->y, p->x); + curve25519_add(b, p->y, p->x); + curve25519_mul(a, a, q->ysubx); + curve25519_mul(x, b, q->xaddy); + curve25519_add(y, x, a); + curve25519_sub(x, x, a); + curve25519_mul(c, p->t, q->t2d); + curve25519_mul(t, p->z, q->z); + curve25519_add(t, t, t); + curve25519_add_after_basic(z, t, c); + curve25519_sub_after_basic(t, t, c); + curve25519_mul(r->xaddy, x, t); + curve25519_mul(r->ysubx, y, z); + curve25519_mul(r->z, z, t); + curve25519_mul(r->t2d, x, y); + curve25519_copy(y, r->ysubx); + curve25519_sub(r->ysubx, r->ysubx, r->xaddy); + curve25519_add(r->xaddy, r->xaddy, y); + curve25519_mul(r->t2d, r->t2d, ge25519_ec2d); +} + +/* + pack & unpack +*/ + +void ge25519_pack(unsigned char r[32], const ge25519* p) { + bignum25519 tx = {0}, ty = {0}, zi = {0}; + unsigned char parity[32] = {0}; + curve25519_recip(zi, p->z); + curve25519_mul(tx, p->x, zi); + curve25519_mul(ty, p->y, zi); + curve25519_contract(r, ty); + curve25519_contract(parity, tx); + r[31] ^= ((parity[0] & 1) << 7); +} + +int ge25519_unpack_negative_vartime(ge25519* r, const unsigned char p[32]) { + const unsigned char zero[32] = {0}; + const bignum25519 one = {1}; + unsigned char parity = p[31] >> 7; + unsigned char check[32] = {0}; + bignum25519 t = {0}, root = {0}, num = {0}, den = {0}, d3 = {0}; + + curve25519_expand(r->y, p); + curve25519_copy(r->z, one); + curve25519_square(num, r->y); /* x = y^2 */ + curve25519_mul(den, num, ge25519_ecd); /* den = dy^2 */ + curve25519_sub_reduce(num, num, r->z); /* x = y^1 - 1 */ + curve25519_add(den, den, r->z); /* den = dy^2 + 1 */ + + /* Computation of sqrt(num/den) */ + /* 1.: computation of num^((p-5)/8)*den^((7p-35)/8) = (num*den^7)^((p-5)/8) */ + curve25519_square(t, den); + curve25519_mul(d3, t, den); + curve25519_square(r->x, d3); + curve25519_mul(r->x, r->x, den); + curve25519_mul(r->x, r->x, num); + curve25519_pow_two252m3(r->x, r->x); + + /* 2. computation of r->x = num * den^3 * (num*den^7)^((p-5)/8) */ + curve25519_mul(r->x, r->x, d3); + curve25519_mul(r->x, r->x, num); + + /* 3. Check if either of the roots works: */ + curve25519_square(t, r->x); + curve25519_mul(t, t, den); + curve25519_sub_reduce(root, t, num); + curve25519_contract(check, root); + if(!ed25519_verify(check, zero, 32)) { + curve25519_add_reduce(t, t, num); + curve25519_contract(check, t); + if(!ed25519_verify(check, zero, 32)) return 0; + curve25519_mul(r->x, r->x, ge25519_sqrtneg1); + } + + curve25519_contract(check, r->x); + if((check[0] & 1) == parity) { + curve25519_copy(t, r->x); + curve25519_neg(r->x, t); + } + curve25519_mul(r->t, r->x, r->y); + return 1; +} + +/* + scalarmults +*/ + +void ge25519_set_neutral(ge25519* r) { + memzero(r, sizeof(ge25519)); + r->y[0] = 1; + r->z[0] = 1; +} + +#define S1_SWINDOWSIZE 5 +#define S1_TABLE_SIZE (1 << (S1_SWINDOWSIZE - 2)) +#ifdef ED25519_NO_PRECOMP +#define S2_SWINDOWSIZE 5 +#else +#define S2_SWINDOWSIZE 7 +#endif +#define S2_TABLE_SIZE (1 << (S2_SWINDOWSIZE - 2)) + +/* computes [s1]p1 + [s2]base */ +void ge25519_double_scalarmult_vartime( + ge25519* r, + const ge25519* p1, + const bignum256modm s1, + const bignum256modm s2) { + signed char slide1[256] = {0}, slide2[256] = {0}; + ge25519_pniels pre1[S1_TABLE_SIZE] = {0}; +#ifdef ED25519_NO_PRECOMP + ge25519_pniels pre2[S2_TABLE_SIZE] = {0}; +#endif + ge25519 dp = {0}; + ge25519_p1p1 t = {0}; + int32_t i = 0; + + memzero(&t, sizeof(ge25519_p1p1)); + contract256_slidingwindow_modm(slide1, s1, S1_SWINDOWSIZE); + contract256_slidingwindow_modm(slide2, s2, S2_SWINDOWSIZE); + + ge25519_double(&dp, p1); + ge25519_full_to_pniels(pre1, p1); + for(i = 0; i < S1_TABLE_SIZE - 1; i++) ge25519_pnielsadd(&pre1[i + 1], &dp, &pre1[i]); + +#ifdef ED25519_NO_PRECOMP + ge25519_double(&dp, &ge25519_basepoint); + ge25519_full_to_pniels(pre2, &ge25519_basepoint); + for(i = 0; i < S2_TABLE_SIZE - 1; i++) ge25519_pnielsadd(&pre2[i + 1], &dp, &pre2[i]); +#endif + + ge25519_set_neutral(r); + + i = 255; + while((i >= 0) && !(slide1[i] | slide2[i])) i--; + + for(; i >= 0; i--) { + ge25519_double_p1p1(&t, r); + + if(slide1[i]) { + ge25519_p1p1_to_full(r, &t); + ge25519_pnielsadd_p1p1( + &t, r, &pre1[abs(slide1[i]) / 2], (unsigned char)slide1[i] >> 7); + } + + if(slide2[i]) { + ge25519_p1p1_to_full(r, &t); +#ifdef ED25519_NO_PRECOMP + ge25519_pnielsadd_p1p1( + &t, r, &pre2[abs(slide2[i]) / 2], (unsigned char)slide2[i] >> 7); +#else + ge25519_nielsadd2_p1p1( + &t, + r, + &ge25519_niels_sliding_multiples[abs(slide2[i]) / 2], + (unsigned char)slide2[i] >> 7); +#endif + } + + ge25519_p1p1_to_partial(r, &t); + } + curve25519_mul(r->t, t.x, t.y); + memzero(slide1, sizeof(slide1)); + memzero(slide2, sizeof(slide2)); +} + +/* computes [s1]p1 + [s2]p2 */ +#if USE_MONERO +void ge25519_double_scalarmult_vartime2( + ge25519* r, + const ge25519* p1, + const bignum256modm s1, + const ge25519* p2, + const bignum256modm s2) { + signed char slide1[256] = {0}, slide2[256] = {0}; + ge25519_pniels pre1[S1_TABLE_SIZE] = {0}; + ge25519_pniels pre2[S1_TABLE_SIZE] = {0}; + ge25519 dp = {0}; + ge25519_p1p1 t = {0}; + int32_t i = 0; + + memzero(&t, sizeof(ge25519_p1p1)); + contract256_slidingwindow_modm(slide1, s1, S1_SWINDOWSIZE); + contract256_slidingwindow_modm(slide2, s2, S1_SWINDOWSIZE); + + ge25519_double(&dp, p1); + ge25519_full_to_pniels(pre1, p1); + for(i = 0; i < S1_TABLE_SIZE - 1; i++) ge25519_pnielsadd(&pre1[i + 1], &dp, &pre1[i]); + + ge25519_double(&dp, p2); + ge25519_full_to_pniels(pre2, p2); + for(i = 0; i < S1_TABLE_SIZE - 1; i++) ge25519_pnielsadd(&pre2[i + 1], &dp, &pre2[i]); + + ge25519_set_neutral(r); + + i = 255; + while((i >= 0) && !(slide1[i] | slide2[i])) i--; + + for(; i >= 0; i--) { + ge25519_double_p1p1(&t, r); + + if(slide1[i]) { + ge25519_p1p1_to_full(r, &t); + ge25519_pnielsadd_p1p1( + &t, r, &pre1[abs(slide1[i]) / 2], (unsigned char)slide1[i] >> 7); + } + + if(slide2[i]) { + ge25519_p1p1_to_full(r, &t); + ge25519_pnielsadd_p1p1( + &t, r, &pre2[abs(slide2[i]) / 2], (unsigned char)slide2[i] >> 7); + } + + ge25519_p1p1_to_partial(r, &t); + } + curve25519_mul(r->t, t.x, t.y); + memzero(slide1, sizeof(slide1)); + memzero(slide2, sizeof(slide2)); +} +#endif + +/* + * The following conditional move stuff uses conditional moves. + * I will check on which compilers this works, and provide suitable + * workarounds for those where it doesn't. + * + * This works on gcc 4.x and above with -O3. Don't use -O2, this will + * cause the code to not generate conditional moves. Don't use any -march= + * with less than i686 on x86 + */ +static void ge25519_cmove_stride4(long* r, long* p, long* pos, long* n, int stride) { + long x0 = r[0], x1 = r[1], x2 = r[2], x3 = r[3], y0 = 0, y1 = 0, y2 = 0, y3 = 0; + for(; p < n; p += stride) { + volatile int flag = (p == pos); + y0 = p[0]; + y1 = p[1]; + y2 = p[2]; + y3 = p[3]; + x0 = flag ? y0 : x0; + x1 = flag ? y1 : x1; + x2 = flag ? y2 : x2; + x3 = flag ? y3 : x3; + } + r[0] = x0; + r[1] = x1; + r[2] = x2; + r[3] = x3; +} +#define HAS_CMOVE_STRIDE4 + +static void ge25519_cmove_stride4b(long* r, long* p, long* pos, long* n, int stride) { + long x0 = p[0], x1 = p[1], x2 = p[2], x3 = p[3], y0 = 0, y1 = 0, y2 = 0, y3 = 0; + for(p += stride; p < n; p += stride) { + volatile int flag = (p == pos); + y0 = p[0]; + y1 = p[1]; + y2 = p[2]; + y3 = p[3]; + x0 = flag ? y0 : x0; + x1 = flag ? y1 : x1; + x2 = flag ? y2 : x2; + x3 = flag ? y3 : x3; + } + r[0] = x0; + r[1] = x1; + r[2] = x2; + r[3] = x3; +} +#define HAS_CMOVE_STRIDE4B + +void ge25519_move_conditional_pniels_array( + ge25519_pniels* r, + const ge25519_pniels* p, + int pos, + int n) { +#ifdef HAS_CMOVE_STRIDE4B + size_t i = 0; + for(i = 0; i < sizeof(ge25519_pniels) / sizeof(long); i += 4) { + ge25519_cmove_stride4b( + ((long*)r) + i, + ((long*)p) + i, + ((long*)(p + pos)) + i, + ((long*)(p + n)) + i, + sizeof(ge25519_pniels) / sizeof(long)); + } +#else + size_t i = 0; + for(i = 0; i < n; i++) { + ge25519_move_conditional_pniels(r, p + i, pos == i); + } +#endif +} + +void ge25519_move_conditional_niels_array(ge25519_niels* r, const uint8_t p[8][96], int pos, int n) { + size_t i = 0; + for(i = 0; i < 96 / sizeof(long); i += 4) { + ge25519_cmove_stride4( + ((long*)r) + i, + ((long*)p) + i, + ((long*)(p + pos)) + i, + ((long*)(p + n)) + i, + 96 / sizeof(long)); + } +} + +/* computes [s1]p1, constant time */ +void ge25519_scalarmult(ge25519* r, const ge25519* p1, const bignum256modm s1) { + signed char slide1[64] = {0}; + ge25519_pniels pre1[9] = {0}; + ge25519_pniels pre = {0}; + ge25519 d1 = {0}; + ge25519_p1p1 t = {0}; + int32_t i = 0; + + contract256_window4_modm(slide1, s1); + + ge25519_full_to_pniels(pre1 + 1, p1); + ge25519_double(&d1, p1); + + ge25519_set_neutral(r); + ge25519_full_to_pniels(pre1, r); + + ge25519_full_to_pniels(pre1 + 2, &d1); + for(i = 1; i < 7; i++) { + ge25519_pnielsadd(&pre1[i + 2], &d1, &pre1[i]); + } + + for(i = 63; i >= 0; i--) { + int k = abs(slide1[i]); + ge25519_double_partial(r, r); + ge25519_double_partial(r, r); + ge25519_double_partial(r, r); + ge25519_double_p1p1(&t, r); + ge25519_move_conditional_pniels_array(&pre, pre1, k, 9); + ge25519_p1p1_to_full(r, &t); + ge25519_pnielsadd_p1p1(&t, r, &pre, (unsigned char)slide1[i] >> 7); + ge25519_p1p1_to_partial(r, &t); + } + curve25519_mul(r->t, t.x, t.y); + memzero(slide1, sizeof(slide1)); +} + +void ge25519_scalarmult_base_choose_niels( + ge25519_niels* t, + const uint8_t table[256][96], + uint32_t pos, + signed char b) { + bignum25519 neg = {0}; + uint32_t sign = (uint32_t)((unsigned char)b >> 7); + uint32_t mask = ~(sign - 1); + uint32_t u = (b + mask) ^ mask; + + /* ysubx, xaddy, t2d in packed form. initialize to ysubx = 1, xaddy = 1, t2d = 0 */ + uint8_t packed[96] = {0}; + packed[0] = 1; + packed[32] = 1; + + ge25519_move_conditional_niels_array((ge25519_niels*)packed, &table[pos * 8], u - 1, 8); + + /* expand in to t */ + curve25519_expand(t->ysubx, packed + 0); + curve25519_expand(t->xaddy, packed + 32); + curve25519_expand(t->t2d, packed + 64); + + /* adjust for sign */ + curve25519_swap_conditional(t->ysubx, t->xaddy, sign); + curve25519_neg(neg, t->t2d); + curve25519_swap_conditional(t->t2d, neg, sign); +} + +/* computes [s]basepoint */ +void ge25519_scalarmult_base_niels( + ge25519* r, + const uint8_t basepoint_table[256][96], + const bignum256modm s) { + signed char b[64] = {0}; + uint32_t i = 0; + ge25519_niels t = {0}; + + contract256_window4_modm(b, s); + + ge25519_scalarmult_base_choose_niels(&t, basepoint_table, 0, b[1]); + curve25519_sub_reduce(r->x, t.xaddy, t.ysubx); + curve25519_add_reduce(r->y, t.xaddy, t.ysubx); + memzero(r->z, sizeof(bignum25519)); + curve25519_copy(r->t, t.t2d); + r->z[0] = 2; + for(i = 3; i < 64; i += 2) { + ge25519_scalarmult_base_choose_niels(&t, basepoint_table, i / 2, b[i]); + ge25519_nielsadd2(r, &t); + } + ge25519_double_partial(r, r); + ge25519_double_partial(r, r); + ge25519_double_partial(r, r); + ge25519_double(r, r); + ge25519_scalarmult_base_choose_niels(&t, basepoint_table, 0, b[0]); + curve25519_mul(t.t2d, t.t2d, ge25519_ecd); + ge25519_nielsadd2(r, &t); + for(i = 2; i < 64; i += 2) { + ge25519_scalarmult_base_choose_niels(&t, basepoint_table, i / 2, b[i]); + ge25519_nielsadd2(r, &t); + } +} + +int ge25519_check(const ge25519* r) { + /* return (z % q != 0 and + x * y % q == z * t % q and + (y * y - x * x - z * z - ed25519.d * t * t) % q == 0) + */ + + bignum25519 z = {0}, lhs = {0}, rhs = {0}, tmp = {0}, res = {0}; + curve25519_reduce(z, r->z); + + curve25519_mul(lhs, r->x, r->y); + curve25519_mul(rhs, r->z, r->t); + curve25519_sub_reduce(lhs, lhs, rhs); + + curve25519_square(res, r->y); + curve25519_square(tmp, r->x); + curve25519_sub_reduce(res, res, tmp); + curve25519_square(tmp, r->z); + curve25519_sub_reduce(res, res, tmp); + curve25519_square(tmp, r->t); + curve25519_mul(tmp, tmp, ge25519_ecd); + curve25519_sub_reduce(res, res, tmp); + + const int c1 = curve25519_isnonzero(z); + const int c2 = curve25519_isnonzero(lhs); + const int c3 = curve25519_isnonzero(res); + return c1 & (c2 ^ 0x1) & (c3 ^ 0x1); +} + +int ge25519_eq(const ge25519* a, const ge25519* b) { + int eq = 1; + bignum25519 t1 = {0}, t2 = {0}; + + eq &= ge25519_check(a); + eq &= ge25519_check(b); + + curve25519_mul(t1, a->x, b->z); + curve25519_mul(t2, b->x, a->z); + curve25519_sub_reduce(t1, t1, t2); + eq &= curve25519_isnonzero(t1) ^ 1; + + curve25519_mul(t1, a->y, b->z); + curve25519_mul(t2, b->y, a->z); + curve25519_sub_reduce(t1, t1, t2); + eq &= curve25519_isnonzero(t1) ^ 1; + + return eq; +} + +void ge25519_copy(ge25519* dst, const ge25519* src) { + curve25519_copy(dst->x, src->x); + curve25519_copy(dst->y, src->y); + curve25519_copy(dst->z, src->z); + curve25519_copy(dst->t, src->t); +} + +void ge25519_set_base(ge25519* r) { + ge25519_copy(r, &ge25519_basepoint); +} + +void ge25519_mul8(ge25519* r, const ge25519* t) { + ge25519_double_partial(r, t); + ge25519_double_partial(r, r); + ge25519_double(r, r); +} + +void ge25519_neg_partial(ge25519* r) { + curve25519_neg(r->x, r->x); +} + +void ge25519_neg_full(ge25519* r) { + curve25519_neg(r->x, r->x); + curve25519_neg(r->t, r->t); +} + +void ge25519_reduce(ge25519* r, const ge25519* t) { + curve25519_reduce(r->x, t->x); + curve25519_reduce(r->y, t->y); + curve25519_reduce(r->z, t->z); + curve25519_reduce(r->t, t->t); +} + +void ge25519_norm(ge25519* r, const ge25519* t) { + bignum25519 zinv = {0}; + curve25519_recip(zinv, t->z); + curve25519_mul(r->x, t->x, zinv); + curve25519_mul(r->y, t->y, zinv); + curve25519_mul(r->t, r->x, r->y); + curve25519_set(r->z, 1); +} + +void ge25519_add(ge25519* r, const ge25519* p, const ge25519* q, unsigned char signbit) { + ge25519_pniels P_ni = {0}; + ge25519_p1p1 P_11 = {0}; + + ge25519_full_to_pniels(&P_ni, q); + ge25519_pnielsadd_p1p1(&P_11, p, &P_ni, signbit); + ge25519_p1p1_to_full(r, &P_11); +} + +void ge25519_fromfe_frombytes_vartime(ge25519* r, const unsigned char* s) { + bignum25519 u = {0}, v = {0}, w = {0}, x = {0}, y = {0}, z = {0}; + unsigned char sign = 0; + + curve25519_expand_reduce(u, s); + + curve25519_square(v, u); + curve25519_add_reduce(v, v, v); /* 2 * u^2 */ + curve25519_set(w, 1); + curve25519_add_reduce(w, v, w); /* w = 2 * u^2 + 1 */ + + curve25519_square(x, w); /* w^2 */ + curve25519_mul(y, fe_ma2, v); /* -2 * A^2 * u^2 */ + curve25519_add_reduce(x, x, y); /* x = w^2 - 2 * A^2 * u^2 */ + + curve25519_divpowm1(r->x, w, x); /* (w / x)^(m + 1) */ + curve25519_square(y, r->x); + curve25519_mul(x, y, x); + curve25519_sub_reduce(y, w, x); + curve25519_copy(z, fe_ma); + + if(curve25519_isnonzero(y)) { + curve25519_add_reduce(y, w, x); + if(curve25519_isnonzero(y)) { + goto negative; + } else { + curve25519_mul(r->x, r->x, fe_fffb1); + } + } else { + curve25519_mul(r->x, r->x, fe_fffb2); + } + curve25519_mul(r->x, r->x, u); /* u * sqrt(2 * A * (A + 2) * w / x) */ + curve25519_mul(z, z, v); /* -2 * A * u^2 */ + sign = 0; + goto setsign; +negative: + curve25519_mul(x, x, fe_sqrtm1); + curve25519_sub_reduce(y, w, x); + if(curve25519_isnonzero(y)) { + assert((curve25519_add_reduce(y, w, x), !curve25519_isnonzero(y))); + curve25519_mul(r->x, r->x, fe_fffb3); + } else { + curve25519_mul(r->x, r->x, fe_fffb4); + } + /* r->x = sqrt(A * (A + 2) * w / x) */ + /* z = -A */ + sign = 1; +setsign: + if(curve25519_isnegative(r->x) != sign) { + assert(curve25519_isnonzero(r->x)); + curve25519_neg(r->x, r->x); + } + curve25519_add_reduce(r->z, z, w); + curve25519_sub_reduce(r->y, z, w); + curve25519_mul(r->x, r->x, r->z); + + // Partial form, saving from T coord computation . + // Later is mul8 discarding T anyway. + // rt = ((rx * ry % q) * inv(rz)) % q + // curve25519_mul(x, r->x, r->y); + // curve25519_recip(z, r->z); + // curve25519_mul(r->t, x, z); + +#if !defined(NDEBUG) + { + bignum25519 check_x = {0}, check_y = {0}, check_iz = {0}, check_v = {0}; + curve25519_recip(check_iz, r->z); + curve25519_mul(check_x, r->x, check_iz); + curve25519_mul(check_y, r->y, check_iz); + curve25519_square(check_x, check_x); + curve25519_square(check_y, check_y); + curve25519_mul(check_v, check_x, check_y); + curve25519_mul(check_v, fe_d, check_v); + curve25519_add_reduce(check_v, check_v, check_x); + curve25519_sub_reduce(check_v, check_v, check_y); + curve25519_set(check_x, 1); + curve25519_add_reduce(check_v, check_v, check_x); + assert(!curve25519_isnonzero(check_v)); + } +#endif +} + +int ge25519_unpack_vartime(ge25519* r, const unsigned char* s) { + int res = ge25519_unpack_negative_vartime(r, s); + ge25519_neg_full(r); + return res; +} + +void ge25519_scalarmult_base_wrapper(ge25519* r, const bignum256modm s) { + ge25519_scalarmult_base_niels(r, ge25519_niels_base_multiples, s); +} diff --git a/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_donna_impl_base.h b/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_donna_impl_base.h new file mode 100644 index 000000000..8e690ef80 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_donna_impl_base.h @@ -0,0 +1,127 @@ +/* + Timing safe memory compare +*/ +int ed25519_verify(const unsigned char* x, const unsigned char* y, size_t len); + +/* + conversions +*/ + +void ge25519_p1p1_to_partial(ge25519* r, const ge25519_p1p1* p); + +void ge25519_p1p1_to_full(ge25519* r, const ge25519_p1p1* p); + +void ge25519_full_to_pniels(ge25519_pniels* p, const ge25519* r); + +/* + adding & doubling +*/ + +void ge25519_double_p1p1(ge25519_p1p1* r, const ge25519* p); + +#ifndef ED25519_NO_PRECOMP +void ge25519_nielsadd2_p1p1( + ge25519_p1p1* r, + const ge25519* p, + const ge25519_niels* q, + unsigned char signbit); +#endif + +/* computes [s1]p1 + [s2]p2 */ +//#if USE_MONERO +void ge25519_double_scalarmult_vartime2( + ge25519* r, + const ge25519* p1, + const bignum256modm s1, + const ge25519* p2, + const bignum256modm s2); +//#endif + +void ge25519_pnielsadd_p1p1( + ge25519_p1p1* r, + const ge25519* p, + const ge25519_pniels* q, + unsigned char signbit); + +void ge25519_double_partial(ge25519* r, const ge25519* p); + +void ge25519_double(ge25519* r, const ge25519* p); + +void ge25519_nielsadd2(ge25519* r, const ge25519_niels* q); + +void ge25519_pnielsadd(ge25519_pniels* r, const ge25519* p, const ge25519_pniels* q); + +/* + pack & unpack +*/ + +void ge25519_pack(unsigned char r[32], const ge25519* p); + +int ge25519_unpack_negative_vartime(ge25519* r, const unsigned char p[32]); + +/* + scalarmults +*/ + +void ge25519_set_neutral(ge25519* r); + +/* computes [s1]p1 + [s2]base */ +void ge25519_double_scalarmult_vartime( + ge25519* r, + const ge25519* p1, + const bignum256modm s1, + const bignum256modm s2); + +/* computes [s1]p1, constant time */ +void ge25519_scalarmult(ge25519* r, const ge25519* p1, const bignum256modm s1); + +void ge25519_scalarmult_base_choose_niels( + ge25519_niels* t, + const uint8_t table[256][96], + uint32_t pos, + signed char b); + +/* computes [s]basepoint */ +void ge25519_scalarmult_base_niels( + ge25519* r, + const uint8_t basepoint_table[256][96], + const bignum256modm s); + +/* check if r is on curve */ +int ge25519_check(const ge25519* r); + +/* a == b */ +int ge25519_eq(const ge25519* a, const ge25519* b); + +/* copies one point to another */ +void ge25519_copy(ge25519* dst, const ge25519* src); + +/* sets B point to r */ +void ge25519_set_base(ge25519* r); + +/* 8*P */ +void ge25519_mul8(ge25519* r, const ge25519* t); + +/* -P */ +void ge25519_neg_partial(ge25519* r); + +/* -P */ +void ge25519_neg_full(ge25519* r); + +/* reduce all coords */ +void ge25519_reduce(ge25519* r, const ge25519* t); + +/* normalizes coords. (x, y, 1, x*y) */ +void ge25519_norm(ge25519* r, const ge25519* t); + +/* Simple addition */ +void ge25519_add(ge25519* r, const ge25519* a, const ge25519* b, unsigned char signbit); + +/* point from bytes, used in H_p() */ +void ge25519_fromfe_frombytes_vartime(ge25519* r, const unsigned char* s); + +/* point from bytes */ +int ge25519_unpack_vartime(ge25519* r, const unsigned char* s); + +/* aG, wrapper for niels base mult. */ +void ge25519_scalarmult_base_wrapper(ge25519* r, const bignum256modm s); diff --git a/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_donna_portable.h b/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_donna_portable.h new file mode 100644 index 000000000..d344c9e2a --- /dev/null +++ b/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_donna_portable.h @@ -0,0 +1,22 @@ +#define mul32x32_64(a, b) (((uint64_t)(a)) * (b)) + +#include +#include +#include + +#define DONNA_INLINE +#undef ALIGN +#define ALIGN(x) __attribute__((aligned(x))) + +static inline void U32TO8_LE(unsigned char* p, const uint32_t v) { + p[0] = (unsigned char)(v); + p[1] = (unsigned char)(v >> 8); + p[2] = (unsigned char)(v >> 16); + p[3] = (unsigned char)(v >> 24); +} + +static inline uint32_t U8TO32_LE(const unsigned char* p) { + return ( + ((uint32_t)(p[0])) | ((uint32_t)(p[1]) << 8) | ((uint32_t)(p[2]) << 16) | + ((uint32_t)(p[3]) << 24)); +} diff --git a/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_hash_custom.h b/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_hash_custom.h new file mode 100644 index 000000000..7bae63ed1 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_hash_custom.h @@ -0,0 +1,23 @@ +/* + a custom hash must have a 512bit digest and implement: + + struct ed25519_hash_context; + + void ed25519_hash_init(ed25519_hash_context *ctx); + void ed25519_hash_update(ed25519_hash_context *ctx, const uint8_t *in, size_t inlen); + void ed25519_hash_final(ed25519_hash_context *ctx, uint8_t *hash); + void ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen); +*/ + +#ifndef ED25519_HASH_CUSTOM +#define ED25519_HASH_CUSTOM + +#include "../sha2.h" + +#define ed25519_hash_context SHA512_CTX +#define ed25519_hash_init(ctx) sha512_Init(ctx) +#define ed25519_hash_update(ctx, in, inlen) sha512_Update((ctx), (in), (inlen)) +#define ed25519_hash_final(ctx, hash) sha512_Final((ctx), (hash)) +#define ed25519_hash(hash, in, inlen) sha512_Raw((in), (inlen), (hash)) + +#endif // ED25519_HASH_CUSTOM diff --git a/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_hash_custom_keccak.h b/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_hash_custom_keccak.h new file mode 100644 index 000000000..74a986824 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_hash_custom_keccak.h @@ -0,0 +1,29 @@ +/* + a custom hash must have a 512bit digest and implement: + + struct ed25519_hash_context; + + void ed25519_hash_init(ed25519_hash_context *ctx); + void ed25519_hash_update(ed25519_hash_context *ctx, const uint8_t *in, size_t inlen); + void ed25519_hash_final(ed25519_hash_context *ctx, uint8_t *hash); + void ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen); +*/ + +#include "../options.h" + +#if USE_KECCAK + +#ifndef ED25519_HASH_CUSTOM +#define ED25519_HASH_CUSTOM + +#include "../sha3.h" + +#define ed25519_hash_context SHA3_CTX +#define ed25519_hash_init(ctx) keccak_512_Init(ctx) +#define ed25519_hash_update(ctx, in, inlen) keccak_Update((ctx), (in), (inlen)) +#define ed25519_hash_final(ctx, hash) keccak_Final((ctx), (hash)) +#define ed25519_hash(hash, in, inlen) keccak_512((in), (inlen), (hash)) + +#endif // ED25519_HASH_CUSTOM + +#endif // USE_KECCAK diff --git a/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_hash_custom_sha3.h b/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_hash_custom_sha3.h new file mode 100644 index 000000000..f857821fa --- /dev/null +++ b/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_hash_custom_sha3.h @@ -0,0 +1,23 @@ +/* + a custom hash must have a 512bit digest and implement: + + struct ed25519_hash_context; + + void ed25519_hash_init(ed25519_hash_context *ctx); + void ed25519_hash_update(ed25519_hash_context *ctx, const uint8_t *in, size_t inlen); + void ed25519_hash_final(ed25519_hash_context *ctx, uint8_t *hash); + void ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen); +*/ + +#ifndef ED25519_HASH_CUSTOM +#define ED25519_HASH_CUSTOM + +#include "../sha3.h" + +#define ed25519_hash_context SHA3_CTX +#define ed25519_hash_init(ctx) sha3_512_Init(ctx) +#define ed25519_hash_update(ctx, in, inlen) sha3_Update((ctx), (in), (inlen)) +#define ed25519_hash_final(ctx, hash) sha3_Final((ctx), (hash)) +#define ed25519_hash(hash, in, inlen) sha3_512((in), (inlen), (hash)) + +#endif // ED25519_HASH_CUSTOM diff --git a/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_keccak.c b/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_keccak.c new file mode 100644 index 000000000..7b33b6bfe --- /dev/null +++ b/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_keccak.c @@ -0,0 +1,14 @@ +#include "../options.h" + +#if USE_KECCAK + +#include + +#include "ed25519_keccak.h" +#include "ed25519_hash_custom_keccak.h" + +#define ED25519_SUFFIX _keccak + +#include "ed25519.c" + +#endif // USE_KECCAK \ No newline at end of file diff --git a/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_keccak.h b/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_keccak.h new file mode 100644 index 000000000..4c315a75e --- /dev/null +++ b/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_keccak.h @@ -0,0 +1,38 @@ +#include "../options.h" + +#if USE_KECCAK + +#ifndef ED25519_KECCAK_H +#define ED25519_KECCAK_H + +#include "ed25519.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +void ed25519_publickey_keccak(const ed25519_secret_key sk, ed25519_public_key pk); + +int ed25519_sign_open_keccak( + const unsigned char* m, + size_t mlen, + const ed25519_public_key pk, + const ed25519_signature RS); +void ed25519_sign_keccak( + const unsigned char* m, + size_t mlen, + const ed25519_secret_key sk, + ed25519_signature RS); + +int ed25519_scalarmult_keccak( + ed25519_public_key res, + const ed25519_secret_key sk, + const ed25519_public_key pk); + +#if defined(__cplusplus) +} +#endif + +#endif // ED25519_KECCAK_H + +#endif // USE_KECCAK \ No newline at end of file diff --git a/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_sha3.c b/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_sha3.c new file mode 100644 index 000000000..e172ef874 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_sha3.c @@ -0,0 +1,8 @@ +#include + +#include "ed25519_sha3.h" +#include "ed25519_hash_custom_sha3.h" + +#define ED25519_SUFFIX _sha3 + +#include "ed25519.c" diff --git a/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_sha3.h b/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_sha3.h new file mode 100644 index 000000000..1085c1b20 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/ed25519_donna/ed25519_sha3.h @@ -0,0 +1,32 @@ +#ifndef ED25519_SHA3_H +#define ED25519_SHA3_H + +#include "ed25519.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +void ed25519_publickey_sha3(const ed25519_secret_key sk, ed25519_public_key pk); + +int ed25519_sign_open_sha3( + const unsigned char* m, + size_t mlen, + const ed25519_public_key pk, + const ed25519_signature RS); +void ed25519_sign_sha3( + const unsigned char* m, + size_t mlen, + const ed25519_secret_key sk, + ed25519_signature RS); + +int ed25519_scalarmult_sha3( + ed25519_public_key res, + const ed25519_secret_key sk, + const ed25519_public_key pk); + +#if defined(__cplusplus) +} +#endif + +#endif // ED25519_SHA3_H diff --git a/applications/external/flipbip/lib/crypto/ed25519_donna/modm_donna_32bit.c b/applications/external/flipbip/lib/crypto/ed25519_donna/modm_donna_32bit.c new file mode 100644 index 000000000..6489ea20c --- /dev/null +++ b/applications/external/flipbip/lib/crypto/ed25519_donna/modm_donna_32bit.c @@ -0,0 +1,800 @@ +/* + Public domain by Andrew M. +*/ + +#include "ed25519_donna.h" + +/* + Arithmetic modulo the group order n = 2^252 + 27742317777372353535851937790883648493 = 7237005577332262213973186563042994240857116359379907606001950938285454250989 + + k = 32 + b = 1 << 8 = 256 + m = 2^252 + 27742317777372353535851937790883648493 = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed + mu = floor( b^(k*2) / m ) = 0xfffffffffffffffffffffffffffffffeb2106215d086329a7ed9ce5a30a2c131b +*/ + +static const bignum256modm modm_m = { + 0x1cf5d3ed, + 0x20498c69, + 0x2f79cd65, + 0x37be77a8, + 0x00000014, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00001000}; + +static const bignum256modm modm_mu = { + 0x0a2c131b, + 0x3673968c, + 0x06329a7e, + 0x01885742, + 0x3fffeb21, + 0x3fffffff, + 0x3fffffff, + 0x3fffffff, + 0x000fffff}; + +static bignum256modm_element_t lt_modm(bignum256modm_element_t a, bignum256modm_element_t b) { + return (a - b) >> 31; +} + +/* see HAC, Alg. 14.42 Step 4 */ +void reduce256_modm(bignum256modm r) { + bignum256modm t = {0}; + bignum256modm_element_t b = 0, pb = 0, mask = 0; + + /* t = r - m */ + pb = 0; + pb += modm_m[0]; + b = lt_modm(r[0], pb); + t[0] = (r[0] - pb + (b << 30)); + pb = b; + pb += modm_m[1]; + b = lt_modm(r[1], pb); + t[1] = (r[1] - pb + (b << 30)); + pb = b; + pb += modm_m[2]; + b = lt_modm(r[2], pb); + t[2] = (r[2] - pb + (b << 30)); + pb = b; + pb += modm_m[3]; + b = lt_modm(r[3], pb); + t[3] = (r[3] - pb + (b << 30)); + pb = b; + pb += modm_m[4]; + b = lt_modm(r[4], pb); + t[4] = (r[4] - pb + (b << 30)); + pb = b; + pb += modm_m[5]; + b = lt_modm(r[5], pb); + t[5] = (r[5] - pb + (b << 30)); + pb = b; + pb += modm_m[6]; + b = lt_modm(r[6], pb); + t[6] = (r[6] - pb + (b << 30)); + pb = b; + pb += modm_m[7]; + b = lt_modm(r[7], pb); + t[7] = (r[7] - pb + (b << 30)); + pb = b; + pb += modm_m[8]; + b = lt_modm(r[8], pb); + t[8] = (r[8] - pb + (b << 16)); + + /* keep r if r was smaller than m */ + mask = b - 1; + r[0] ^= mask & (r[0] ^ t[0]); + r[1] ^= mask & (r[1] ^ t[1]); + r[2] ^= mask & (r[2] ^ t[2]); + r[3] ^= mask & (r[3] ^ t[3]); + r[4] ^= mask & (r[4] ^ t[4]); + r[5] ^= mask & (r[5] ^ t[5]); + r[6] ^= mask & (r[6] ^ t[6]); + r[7] ^= mask & (r[7] ^ t[7]); + r[8] ^= mask & (r[8] ^ t[8]); +} + +/* + Barrett reduction, see HAC, Alg. 14.42 + + Instead of passing in x, pre-process in to q1 and r1 for efficiency +*/ +void barrett_reduce256_modm(bignum256modm r, const bignum256modm q1, const bignum256modm r1) { + bignum256modm q3 = {0}, r2 = {0}; + uint64_t c = 0; + bignum256modm_element_t f = 0, b = 0, pb = 0; + + /* q1 = x >> 248 = 264 bits = 9 30 bit elements + q2 = mu * q1 + q3 = (q2 / 256(32+1)) = q2 / (2^8)^(32+1) = q2 >> 264 */ + c = mul32x32_64(modm_mu[0], q1[7]) + mul32x32_64(modm_mu[1], q1[6]) + + mul32x32_64(modm_mu[2], q1[5]) + mul32x32_64(modm_mu[3], q1[4]) + + mul32x32_64(modm_mu[4], q1[3]) + mul32x32_64(modm_mu[5], q1[2]) + + mul32x32_64(modm_mu[6], q1[1]) + mul32x32_64(modm_mu[7], q1[0]); + c >>= 30; + c += mul32x32_64(modm_mu[0], q1[8]) + mul32x32_64(modm_mu[1], q1[7]) + + mul32x32_64(modm_mu[2], q1[6]) + mul32x32_64(modm_mu[3], q1[5]) + + mul32x32_64(modm_mu[4], q1[4]) + mul32x32_64(modm_mu[5], q1[3]) + + mul32x32_64(modm_mu[6], q1[2]) + mul32x32_64(modm_mu[7], q1[1]) + + mul32x32_64(modm_mu[8], q1[0]); + f = (bignum256modm_element_t)c; + q3[0] = (f >> 24) & 0x3f; + c >>= 30; + c += mul32x32_64(modm_mu[1], q1[8]) + mul32x32_64(modm_mu[2], q1[7]) + + mul32x32_64(modm_mu[3], q1[6]) + mul32x32_64(modm_mu[4], q1[5]) + + mul32x32_64(modm_mu[5], q1[4]) + mul32x32_64(modm_mu[6], q1[3]) + + mul32x32_64(modm_mu[7], q1[2]) + mul32x32_64(modm_mu[8], q1[1]); + f = (bignum256modm_element_t)c; + q3[0] |= (f << 6) & 0x3fffffff; + q3[1] = (f >> 24) & 0x3f; + c >>= 30; + c += mul32x32_64(modm_mu[2], q1[8]) + mul32x32_64(modm_mu[3], q1[7]) + + mul32x32_64(modm_mu[4], q1[6]) + mul32x32_64(modm_mu[5], q1[5]) + + mul32x32_64(modm_mu[6], q1[4]) + mul32x32_64(modm_mu[7], q1[3]) + + mul32x32_64(modm_mu[8], q1[2]); + f = (bignum256modm_element_t)c; + q3[1] |= (f << 6) & 0x3fffffff; + q3[2] = (f >> 24) & 0x3f; + c >>= 30; + c += mul32x32_64(modm_mu[3], q1[8]) + mul32x32_64(modm_mu[4], q1[7]) + + mul32x32_64(modm_mu[5], q1[6]) + mul32x32_64(modm_mu[6], q1[5]) + + mul32x32_64(modm_mu[7], q1[4]) + mul32x32_64(modm_mu[8], q1[3]); + f = (bignum256modm_element_t)c; + q3[2] |= (f << 6) & 0x3fffffff; + q3[3] = (f >> 24) & 0x3f; + c >>= 30; + c += mul32x32_64(modm_mu[4], q1[8]) + mul32x32_64(modm_mu[5], q1[7]) + + mul32x32_64(modm_mu[6], q1[6]) + mul32x32_64(modm_mu[7], q1[5]) + + mul32x32_64(modm_mu[8], q1[4]); + f = (bignum256modm_element_t)c; + q3[3] |= (f << 6) & 0x3fffffff; + q3[4] = (f >> 24) & 0x3f; + c >>= 30; + c += mul32x32_64(modm_mu[5], q1[8]) + mul32x32_64(modm_mu[6], q1[7]) + + mul32x32_64(modm_mu[7], q1[6]) + mul32x32_64(modm_mu[8], q1[5]); + f = (bignum256modm_element_t)c; + q3[4] |= (f << 6) & 0x3fffffff; + q3[5] = (f >> 24) & 0x3f; + c >>= 30; + c += mul32x32_64(modm_mu[6], q1[8]) + mul32x32_64(modm_mu[7], q1[7]) + + mul32x32_64(modm_mu[8], q1[6]); + f = (bignum256modm_element_t)c; + q3[5] |= (f << 6) & 0x3fffffff; + q3[6] = (f >> 24) & 0x3f; + c >>= 30; + c += mul32x32_64(modm_mu[7], q1[8]) + mul32x32_64(modm_mu[8], q1[7]); + f = (bignum256modm_element_t)c; + q3[6] |= (f << 6) & 0x3fffffff; + q3[7] = (f >> 24) & 0x3f; + c >>= 30; + c += mul32x32_64(modm_mu[8], q1[8]); + f = (bignum256modm_element_t)c; + q3[7] |= (f << 6) & 0x3fffffff; + q3[8] = (bignum256modm_element_t)(c >> 24); + + /* r1 = (x mod 256^(32+1)) = x mod (2^8)(32+1) = x & ((1 << 264) - 1) + r2 = (q3 * m) mod (256^(32+1)) = (q3 * m) & ((1 << 264) - 1) */ + c = mul32x32_64(modm_m[0], q3[0]); + r2[0] = (bignum256modm_element_t)(c & 0x3fffffff); + c >>= 30; + c += mul32x32_64(modm_m[0], q3[1]) + mul32x32_64(modm_m[1], q3[0]); + r2[1] = (bignum256modm_element_t)(c & 0x3fffffff); + c >>= 30; + c += mul32x32_64(modm_m[0], q3[2]) + mul32x32_64(modm_m[1], q3[1]) + + mul32x32_64(modm_m[2], q3[0]); + r2[2] = (bignum256modm_element_t)(c & 0x3fffffff); + c >>= 30; + c += mul32x32_64(modm_m[0], q3[3]) + mul32x32_64(modm_m[1], q3[2]) + + mul32x32_64(modm_m[2], q3[1]) + mul32x32_64(modm_m[3], q3[0]); + r2[3] = (bignum256modm_element_t)(c & 0x3fffffff); + c >>= 30; + c += mul32x32_64(modm_m[0], q3[4]) + mul32x32_64(modm_m[1], q3[3]) + + mul32x32_64(modm_m[2], q3[2]) + mul32x32_64(modm_m[3], q3[1]) + + mul32x32_64(modm_m[4], q3[0]); + r2[4] = (bignum256modm_element_t)(c & 0x3fffffff); + c >>= 30; + c += mul32x32_64(modm_m[0], q3[5]) + mul32x32_64(modm_m[1], q3[4]) + + mul32x32_64(modm_m[2], q3[3]) + mul32x32_64(modm_m[3], q3[2]) + + mul32x32_64(modm_m[4], q3[1]) + mul32x32_64(modm_m[5], q3[0]); + r2[5] = (bignum256modm_element_t)(c & 0x3fffffff); + c >>= 30; + c += mul32x32_64(modm_m[0], q3[6]) + mul32x32_64(modm_m[1], q3[5]) + + mul32x32_64(modm_m[2], q3[4]) + mul32x32_64(modm_m[3], q3[3]) + + mul32x32_64(modm_m[4], q3[2]) + mul32x32_64(modm_m[5], q3[1]) + + mul32x32_64(modm_m[6], q3[0]); + r2[6] = (bignum256modm_element_t)(c & 0x3fffffff); + c >>= 30; + c += mul32x32_64(modm_m[0], q3[7]) + mul32x32_64(modm_m[1], q3[6]) + + mul32x32_64(modm_m[2], q3[5]) + mul32x32_64(modm_m[3], q3[4]) + + mul32x32_64(modm_m[4], q3[3]) + mul32x32_64(modm_m[5], q3[2]) + + mul32x32_64(modm_m[6], q3[1]) + mul32x32_64(modm_m[7], q3[0]); + r2[7] = (bignum256modm_element_t)(c & 0x3fffffff); + c >>= 30; + c += mul32x32_64(modm_m[0], q3[8]) + mul32x32_64(modm_m[1], q3[7]) + + mul32x32_64(modm_m[2], q3[6]) + mul32x32_64(modm_m[3], q3[5]) + + mul32x32_64(modm_m[4], q3[4]) + mul32x32_64(modm_m[5], q3[3]) + + mul32x32_64(modm_m[6], q3[2]) + mul32x32_64(modm_m[7], q3[1]) + + mul32x32_64(modm_m[8], q3[0]); + r2[8] = (bignum256modm_element_t)(c & 0xffffff); + + /* r = r1 - r2 + if (r < 0) r += (1 << 264) */ + pb = 0; + pb += r2[0]; + b = lt_modm(r1[0], pb); + r[0] = (r1[0] - pb + (b << 30)); + pb = b; + pb += r2[1]; + b = lt_modm(r1[1], pb); + r[1] = (r1[1] - pb + (b << 30)); + pb = b; + pb += r2[2]; + b = lt_modm(r1[2], pb); + r[2] = (r1[2] - pb + (b << 30)); + pb = b; + pb += r2[3]; + b = lt_modm(r1[3], pb); + r[3] = (r1[3] - pb + (b << 30)); + pb = b; + pb += r2[4]; + b = lt_modm(r1[4], pb); + r[4] = (r1[4] - pb + (b << 30)); + pb = b; + pb += r2[5]; + b = lt_modm(r1[5], pb); + r[5] = (r1[5] - pb + (b << 30)); + pb = b; + pb += r2[6]; + b = lt_modm(r1[6], pb); + r[6] = (r1[6] - pb + (b << 30)); + pb = b; + pb += r2[7]; + b = lt_modm(r1[7], pb); + r[7] = (r1[7] - pb + (b << 30)); + pb = b; + pb += r2[8]; + b = lt_modm(r1[8], pb); + r[8] = (r1[8] - pb + (b << 24)); + + reduce256_modm(r); + reduce256_modm(r); +} + +/* addition modulo m */ +void add256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { + bignum256modm_element_t c = 0; + + c = x[0] + y[0]; + r[0] = c & 0x3fffffff; + c >>= 30; + c += x[1] + y[1]; + r[1] = c & 0x3fffffff; + c >>= 30; + c += x[2] + y[2]; + r[2] = c & 0x3fffffff; + c >>= 30; + c += x[3] + y[3]; + r[3] = c & 0x3fffffff; + c >>= 30; + c += x[4] + y[4]; + r[4] = c & 0x3fffffff; + c >>= 30; + c += x[5] + y[5]; + r[5] = c & 0x3fffffff; + c >>= 30; + c += x[6] + y[6]; + r[6] = c & 0x3fffffff; + c >>= 30; + c += x[7] + y[7]; + r[7] = c & 0x3fffffff; + c >>= 30; + c += x[8] + y[8]; + r[8] = c; + + reduce256_modm(r); +} + +/* -x modulo m */ +void neg256_modm(bignum256modm r, const bignum256modm x) { + bignum256modm_element_t b = 0, pb = 0; + + /* r = m - x */ + pb = 0; + pb += x[0]; + b = lt_modm(modm_m[0], pb); + r[0] = (modm_m[0] - pb + (b << 30)); + pb = b; + pb += x[1]; + b = lt_modm(modm_m[1], pb); + r[1] = (modm_m[1] - pb + (b << 30)); + pb = b; + pb += x[2]; + b = lt_modm(modm_m[2], pb); + r[2] = (modm_m[2] - pb + (b << 30)); + pb = b; + pb += x[3]; + b = lt_modm(modm_m[3], pb); + r[3] = (modm_m[3] - pb + (b << 30)); + pb = b; + pb += x[4]; + b = lt_modm(modm_m[4], pb); + r[4] = (modm_m[4] - pb + (b << 30)); + pb = b; + pb += x[5]; + b = lt_modm(modm_m[5], pb); + r[5] = (modm_m[5] - pb + (b << 30)); + pb = b; + pb += x[6]; + b = lt_modm(modm_m[6], pb); + r[6] = (modm_m[6] - pb + (b << 30)); + pb = b; + pb += x[7]; + b = lt_modm(modm_m[7], pb); + r[7] = (modm_m[7] - pb + (b << 30)); + pb = b; + pb += x[8]; + b = lt_modm(modm_m[8], pb); + r[8] = (modm_m[8] - pb + (b << 16)); + + // if x==0, reduction is required + reduce256_modm(r); +} + +/* consts for subtraction, > p */ +/* Emilia Kasper trick, https://www.imperialviolet.org/2010/12/04/ecc.html */ +static const uint32_t twoP[] = { + 0x5cf5d3ed, + 0x60498c68, + 0x6f79cd64, + 0x77be77a7, + 0x40000013, + 0x3fffffff, + 0x3fffffff, + 0x3fffffff, + 0xfff}; + +/* subtraction x-y % m */ +void sub256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { + bignum256modm_element_t c = 0; + c = twoP[0] + x[0] - y[0]; + r[0] = c & 0x3fffffff; + c >>= 30; + c += twoP[1] + x[1] - y[1]; + r[1] = c & 0x3fffffff; + c >>= 30; + c += twoP[2] + x[2] - y[2]; + r[2] = c & 0x3fffffff; + c >>= 30; + c += twoP[3] + x[3] - y[3]; + r[3] = c & 0x3fffffff; + c >>= 30; + c += twoP[4] + x[4] - y[4]; + r[4] = c & 0x3fffffff; + c >>= 30; + c += twoP[5] + x[5] - y[5]; + r[5] = c & 0x3fffffff; + c >>= 30; + c += twoP[6] + x[6] - y[6]; + r[6] = c & 0x3fffffff; + c >>= 30; + c += twoP[7] + x[7] - y[7]; + r[7] = c & 0x3fffffff; + c >>= 30; + c += twoP[8] + x[8] - y[8]; + r[8] = c; + reduce256_modm(r); +} + +/* multiplication modulo m */ +void mul256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { + bignum256modm r1 = {0}, q1 = {0}; + uint64_t c = 0; + bignum256modm_element_t f = 0; + + /* r1 = (x mod 256^(32+1)) = x mod (2^8)(31+1) = x & ((1 << 264) - 1) + q1 = x >> 248 = 264 bits = 9 30 bit elements */ + c = mul32x32_64(x[0], y[0]); + f = (bignum256modm_element_t)c; + r1[0] = (f & 0x3fffffff); + c >>= 30; + c += mul32x32_64(x[0], y[1]) + mul32x32_64(x[1], y[0]); + f = (bignum256modm_element_t)c; + r1[1] = (f & 0x3fffffff); + c >>= 30; + c += mul32x32_64(x[0], y[2]) + mul32x32_64(x[1], y[1]) + mul32x32_64(x[2], y[0]); + f = (bignum256modm_element_t)c; + r1[2] = (f & 0x3fffffff); + c >>= 30; + c += mul32x32_64(x[0], y[3]) + mul32x32_64(x[1], y[2]) + mul32x32_64(x[2], y[1]) + + mul32x32_64(x[3], y[0]); + f = (bignum256modm_element_t)c; + r1[3] = (f & 0x3fffffff); + c >>= 30; + c += mul32x32_64(x[0], y[4]) + mul32x32_64(x[1], y[3]) + mul32x32_64(x[2], y[2]) + + mul32x32_64(x[3], y[1]) + mul32x32_64(x[4], y[0]); + f = (bignum256modm_element_t)c; + r1[4] = (f & 0x3fffffff); + c >>= 30; + c += mul32x32_64(x[0], y[5]) + mul32x32_64(x[1], y[4]) + mul32x32_64(x[2], y[3]) + + mul32x32_64(x[3], y[2]) + mul32x32_64(x[4], y[1]) + mul32x32_64(x[5], y[0]); + f = (bignum256modm_element_t)c; + r1[5] = (f & 0x3fffffff); + c >>= 30; + c += mul32x32_64(x[0], y[6]) + mul32x32_64(x[1], y[5]) + mul32x32_64(x[2], y[4]) + + mul32x32_64(x[3], y[3]) + mul32x32_64(x[4], y[2]) + mul32x32_64(x[5], y[1]) + + mul32x32_64(x[6], y[0]); + f = (bignum256modm_element_t)c; + r1[6] = (f & 0x3fffffff); + c >>= 30; + c += mul32x32_64(x[0], y[7]) + mul32x32_64(x[1], y[6]) + mul32x32_64(x[2], y[5]) + + mul32x32_64(x[3], y[4]) + mul32x32_64(x[4], y[3]) + mul32x32_64(x[5], y[2]) + + mul32x32_64(x[6], y[1]) + mul32x32_64(x[7], y[0]); + f = (bignum256modm_element_t)c; + r1[7] = (f & 0x3fffffff); + c >>= 30; + c += mul32x32_64(x[0], y[8]) + mul32x32_64(x[1], y[7]) + mul32x32_64(x[2], y[6]) + + mul32x32_64(x[3], y[5]) + mul32x32_64(x[4], y[4]) + mul32x32_64(x[5], y[3]) + + mul32x32_64(x[6], y[2]) + mul32x32_64(x[7], y[1]) + mul32x32_64(x[8], y[0]); + f = (bignum256modm_element_t)c; + r1[8] = (f & 0x00ffffff); + q1[0] = (f >> 8) & 0x3fffff; + c >>= 30; + c += mul32x32_64(x[1], y[8]) + mul32x32_64(x[2], y[7]) + mul32x32_64(x[3], y[6]) + + mul32x32_64(x[4], y[5]) + mul32x32_64(x[5], y[4]) + mul32x32_64(x[6], y[3]) + + mul32x32_64(x[7], y[2]) + mul32x32_64(x[8], y[1]); + f = (bignum256modm_element_t)c; + q1[0] = (q1[0] | (f << 22)) & 0x3fffffff; + q1[1] = (f >> 8) & 0x3fffff; + c >>= 30; + c += mul32x32_64(x[2], y[8]) + mul32x32_64(x[3], y[7]) + mul32x32_64(x[4], y[6]) + + mul32x32_64(x[5], y[5]) + mul32x32_64(x[6], y[4]) + mul32x32_64(x[7], y[3]) + + mul32x32_64(x[8], y[2]); + f = (bignum256modm_element_t)c; + q1[1] = (q1[1] | (f << 22)) & 0x3fffffff; + q1[2] = (f >> 8) & 0x3fffff; + c >>= 30; + c += mul32x32_64(x[3], y[8]) + mul32x32_64(x[4], y[7]) + mul32x32_64(x[5], y[6]) + + mul32x32_64(x[6], y[5]) + mul32x32_64(x[7], y[4]) + mul32x32_64(x[8], y[3]); + f = (bignum256modm_element_t)c; + q1[2] = (q1[2] | (f << 22)) & 0x3fffffff; + q1[3] = (f >> 8) & 0x3fffff; + c >>= 30; + c += mul32x32_64(x[4], y[8]) + mul32x32_64(x[5], y[7]) + mul32x32_64(x[6], y[6]) + + mul32x32_64(x[7], y[5]) + mul32x32_64(x[8], y[4]); + f = (bignum256modm_element_t)c; + q1[3] = (q1[3] | (f << 22)) & 0x3fffffff; + q1[4] = (f >> 8) & 0x3fffff; + c >>= 30; + c += mul32x32_64(x[5], y[8]) + mul32x32_64(x[6], y[7]) + mul32x32_64(x[7], y[6]) + + mul32x32_64(x[8], y[5]); + f = (bignum256modm_element_t)c; + q1[4] = (q1[4] | (f << 22)) & 0x3fffffff; + q1[5] = (f >> 8) & 0x3fffff; + c >>= 30; + c += mul32x32_64(x[6], y[8]) + mul32x32_64(x[7], y[7]) + mul32x32_64(x[8], y[6]); + f = (bignum256modm_element_t)c; + q1[5] = (q1[5] | (f << 22)) & 0x3fffffff; + q1[6] = (f >> 8) & 0x3fffff; + c >>= 30; + c += mul32x32_64(x[7], y[8]) + mul32x32_64(x[8], y[7]); + f = (bignum256modm_element_t)c; + q1[6] = (q1[6] | (f << 22)) & 0x3fffffff; + q1[7] = (f >> 8) & 0x3fffff; + c >>= 30; + c += mul32x32_64(x[8], y[8]); + f = (bignum256modm_element_t)c; + q1[7] = (q1[7] | (f << 22)) & 0x3fffffff; + q1[8] = (f >> 8) & 0x3fffff; + + barrett_reduce256_modm(r, q1, r1); +} + +void expand256_modm(bignum256modm out, const unsigned char* in, size_t len) { + unsigned char work[64] = {0}; + bignum256modm_element_t x[16] = {0}; + bignum256modm q1 = {0}; + + memcpy(work, in, len); + x[0] = U8TO32_LE(work + 0); + x[1] = U8TO32_LE(work + 4); + x[2] = U8TO32_LE(work + 8); + x[3] = U8TO32_LE(work + 12); + x[4] = U8TO32_LE(work + 16); + x[5] = U8TO32_LE(work + 20); + x[6] = U8TO32_LE(work + 24); + x[7] = U8TO32_LE(work + 28); + x[8] = U8TO32_LE(work + 32); + x[9] = U8TO32_LE(work + 36); + x[10] = U8TO32_LE(work + 40); + x[11] = U8TO32_LE(work + 44); + x[12] = U8TO32_LE(work + 48); + x[13] = U8TO32_LE(work + 52); + x[14] = U8TO32_LE(work + 56); + x[15] = U8TO32_LE(work + 60); + + /* r1 = (x mod 256^(32+1)) = x mod (2^8)(31+1) = x & ((1 << 264) - 1) */ + out[0] = (x[0]) & 0x3fffffff; + out[1] = ((x[0] >> 30) | (x[1] << 2)) & 0x3fffffff; + out[2] = ((x[1] >> 28) | (x[2] << 4)) & 0x3fffffff; + out[3] = ((x[2] >> 26) | (x[3] << 6)) & 0x3fffffff; + out[4] = ((x[3] >> 24) | (x[4] << 8)) & 0x3fffffff; + out[5] = ((x[4] >> 22) | (x[5] << 10)) & 0x3fffffff; + out[6] = ((x[5] >> 20) | (x[6] << 12)) & 0x3fffffff; + out[7] = ((x[6] >> 18) | (x[7] << 14)) & 0x3fffffff; + out[8] = ((x[7] >> 16) | (x[8] << 16)) & 0x00ffffff; + + /* 8*31 = 248 bits, no need to reduce */ + if(len < 32) return; + + /* q1 = x >> 248 = 264 bits = 9 30 bit elements */ + q1[0] = ((x[7] >> 24) | (x[8] << 8)) & 0x3fffffff; + q1[1] = ((x[8] >> 22) | (x[9] << 10)) & 0x3fffffff; + q1[2] = ((x[9] >> 20) | (x[10] << 12)) & 0x3fffffff; + q1[3] = ((x[10] >> 18) | (x[11] << 14)) & 0x3fffffff; + q1[4] = ((x[11] >> 16) | (x[12] << 16)) & 0x3fffffff; + q1[5] = ((x[12] >> 14) | (x[13] << 18)) & 0x3fffffff; + q1[6] = ((x[13] >> 12) | (x[14] << 20)) & 0x3fffffff; + q1[7] = ((x[14] >> 10) | (x[15] << 22)) & 0x3fffffff; + q1[8] = ((x[15] >> 8)); + + barrett_reduce256_modm(out, q1, out); +} + +void expand_raw256_modm(bignum256modm out, const unsigned char in[32]) { + bignum256modm_element_t x[8] = {0}; + + x[0] = U8TO32_LE(in + 0); + x[1] = U8TO32_LE(in + 4); + x[2] = U8TO32_LE(in + 8); + x[3] = U8TO32_LE(in + 12); + x[4] = U8TO32_LE(in + 16); + x[5] = U8TO32_LE(in + 20); + x[6] = U8TO32_LE(in + 24); + x[7] = U8TO32_LE(in + 28); + + out[0] = (x[0]) & 0x3fffffff; + out[1] = ((x[0] >> 30) | (x[1] << 2)) & 0x3fffffff; + out[2] = ((x[1] >> 28) | (x[2] << 4)) & 0x3fffffff; + out[3] = ((x[2] >> 26) | (x[3] << 6)) & 0x3fffffff; + out[4] = ((x[3] >> 24) | (x[4] << 8)) & 0x3fffffff; + out[5] = ((x[4] >> 22) | (x[5] << 10)) & 0x3fffffff; + out[6] = ((x[5] >> 20) | (x[6] << 12)) & 0x3fffffff; + out[7] = ((x[6] >> 18) | (x[7] << 14)) & 0x3fffffff; + out[8] = ((x[7] >> 16)) & 0x0000ffff; +} + +int is_reduced256_modm(const bignum256modm in) { + int i = 0; + uint32_t res1 = 0; + uint32_t res2 = 0; + for(i = 8; i >= 0; i--) { + res1 = (res1 << 1) | (in[i] < modm_m[i]); + res2 = (res2 << 1) | (in[i] > modm_m[i]); + } + return res1 > res2; +} + +void contract256_modm(unsigned char out[32], const bignum256modm in) { + U32TO8_LE(out + 0, (in[0]) | (in[1] << 30)); + U32TO8_LE(out + 4, (in[1] >> 2) | (in[2] << 28)); + U32TO8_LE(out + 8, (in[2] >> 4) | (in[3] << 26)); + U32TO8_LE(out + 12, (in[3] >> 6) | (in[4] << 24)); + U32TO8_LE(out + 16, (in[4] >> 8) | (in[5] << 22)); + U32TO8_LE(out + 20, (in[5] >> 10) | (in[6] << 20)); + U32TO8_LE(out + 24, (in[6] >> 12) | (in[7] << 18)); + U32TO8_LE(out + 28, (in[7] >> 14) | (in[8] << 16)); +} + +void contract256_window4_modm(signed char r[64], const bignum256modm in) { + char carry = 0; + signed char* quads = r; + bignum256modm_element_t i = 0, j = 0, v = 0; + + for(i = 0; i < 8; i += 2) { + v = in[i]; + for(j = 0; j < 7; j++) { + *quads++ = (v & 15); + v >>= 4; + } + v |= (in[i + 1] << 2); + for(j = 0; j < 8; j++) { + *quads++ = (v & 15); + v >>= 4; + } + } + v = in[8]; + *quads++ = (v & 15); + v >>= 4; + *quads++ = (v & 15); + v >>= 4; + *quads++ = (v & 15); + v >>= 4; + *quads++ = (v & 15); + v >>= 4; + + /* making it signed */ + carry = 0; + for(i = 0; i < 63; i++) { + r[i] += carry; + r[i + 1] += (r[i] >> 4); + r[i] &= 15; + carry = (r[i] >> 3); + r[i] -= (carry << 4); + } + r[63] += carry; +} + +void contract256_slidingwindow_modm(signed char r[256], const bignum256modm s, int windowsize) { + int i = 0, j = 0, k = 0, b = 0; + int m = (1 << (windowsize - 1)) - 1, soplen = 256; + signed char* bits = r; + bignum256modm_element_t v = 0; + + /* first put the binary expansion into r */ + for(i = 0; i < 8; i++) { + v = s[i]; + for(j = 0; j < 30; j++, v >>= 1) *bits++ = (v & 1); + } + v = s[8]; + for(j = 0; j < 16; j++, v >>= 1) *bits++ = (v & 1); + + /* Making it sliding window */ + for(j = 0; j < soplen; j++) { + if(!r[j]) continue; + + for(b = 1; (b < (soplen - j)) && (b <= 6); b++) { + if((r[j] + (r[j + b] << b)) <= m) { + r[j] += r[j + b] << b; + r[j + b] = 0; + } else if((r[j] - (r[j + b] << b)) >= -m) { + r[j] -= r[j + b] << b; + for(k = j + b; k < soplen; k++) { + if(!r[k]) { + r[k] = 1; + break; + } + r[k] = 0; + } + } else if(r[j + b]) { + break; + } + } + } +} + +void set256_modm(bignum256modm r, uint64_t v) { + r[0] = (bignum256modm_element_t)(v & 0x3fffffff); + v >>= 30; + r[1] = (bignum256modm_element_t)(v & 0x3fffffff); + v >>= 30; + r[2] = (bignum256modm_element_t)(v & 0x3fffffff); + r[3] = 0; + r[4] = 0; + r[5] = 0; + r[6] = 0; + r[7] = 0; + r[8] = 0; +} + +int get256_modm(uint64_t* v, const bignum256modm r) { + *v = 0; + int con1 = 0; + +#define NONZ(x) ((((((int64_t)(x)) - 1) >> 32) + 1) & 1) + bignum256modm_element_t c = 0; + c = r[0]; + *v += (uint64_t)c & 0x3fffffff; + c >>= 30; // 30 + c += r[1]; + *v += ((uint64_t)c & 0x3fffffff) << 30; + c >>= 30; // 60 + c += r[2]; + *v += ((uint64_t)c & 0xf) << 60; + con1 |= NONZ(c >> 4); + c >>= 30; // 64 bits + c += r[3]; + con1 |= NONZ(c); + c >>= 30; + c += r[4]; + con1 |= NONZ(c); + c >>= 30; + c += r[5]; + con1 |= NONZ(c); + c >>= 30; + c += r[6]; + con1 |= NONZ(c); + c >>= 30; + c += r[7]; + con1 |= NONZ(c); + c >>= 30; + c += r[8]; + con1 |= NONZ(c); + c >>= 30; + con1 |= NONZ(c); +#undef NONZ + + return con1 ^ 1; +} + +int eq256_modm(const bignum256modm x, const bignum256modm y) { + size_t differentbits = 0; + int len = bignum256modm_limb_size; + while(len--) { + differentbits |= (*x++ ^ *y++); + } + return (int)(1 & ((differentbits - 1) >> bignum256modm_bits_per_limb)); +} + +int cmp256_modm(const bignum256modm x, const bignum256modm y) { + int len = 2 * bignum256modm_limb_size; + uint32_t a_gt = 0; + uint32_t b_gt = 0; + + // 16B chunks + while(len--) { + const uint32_t ln = (const uint32_t)len; + const uint32_t a = (x[ln >> 1] >> 16 * (ln & 1)) & 0xffff; + const uint32_t b = (y[ln >> 1] >> 16 * (ln & 1)) & 0xffff; + + const uint32_t limb_a_gt = ((b - a) >> 16) & 1; + const uint32_t limb_b_gt = ((a - b) >> 16) & 1; + a_gt |= limb_a_gt & ~b_gt; + b_gt |= limb_b_gt & ~a_gt; + } + + return a_gt - b_gt; +} + +int iszero256_modm(const bignum256modm x) { + size_t differentbits = 0; + int len = bignum256modm_limb_size; + while(len--) { + differentbits |= (*x++); + } + return (int)(1 & ((differentbits - 1) >> bignum256modm_bits_per_limb)); +} + +void copy256_modm(bignum256modm r, const bignum256modm x) { + r[0] = x[0]; + r[1] = x[1]; + r[2] = x[2]; + r[3] = x[3]; + r[4] = x[4]; + r[5] = x[5]; + r[6] = x[6]; + r[7] = x[7]; + r[8] = x[8]; +} + +int check256_modm(const bignum256modm x) { + int ok = 1; + bignum256modm t = {0}, z = {0}; + + ok &= iszero256_modm(x) ^ 1; + barrett_reduce256_modm(t, z, x); + ok &= eq256_modm(t, x); + return ok; +} + +void mulsub256_modm( + bignum256modm r, + const bignum256modm a, + const bignum256modm b, + const bignum256modm c) { + //(cc - aa * bb) % l + bignum256modm t = {0}; + mul256_modm(t, a, b); + sub256_modm(r, c, t); +} + +void muladd256_modm( + bignum256modm r, + const bignum256modm a, + const bignum256modm b, + const bignum256modm c) { + //(cc + aa * bb) % l + bignum256modm t = {0}; + mul256_modm(t, a, b); + add256_modm(r, c, t); +} diff --git a/applications/external/flipbip/lib/crypto/ed25519_donna/modm_donna_32bit.h b/applications/external/flipbip/lib/crypto/ed25519_donna/modm_donna_32bit.h new file mode 100644 index 000000000..021edc19e --- /dev/null +++ b/applications/external/flipbip/lib/crypto/ed25519_donna/modm_donna_32bit.h @@ -0,0 +1,87 @@ +/* + Public domain by Andrew M. +*/ + +/* + Arithmetic modulo the group order n = 2^252 + 27742317777372353535851937790883648493 = 7237005577332262213973186563042994240857116359379907606001950938285454250989 + + k = 32 + b = 1 << 8 = 256 + m = 2^252 + 27742317777372353535851937790883648493 = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed + mu = floor( b^(k*2) / m ) = 0xfffffffffffffffffffffffffffffffeb2106215d086329a7ed9ce5a30a2c131b +*/ + +#define bignum256modm_bits_per_limb 30 +#define bignum256modm_limb_size 9 + +typedef uint32_t bignum256modm_element_t; +typedef bignum256modm_element_t bignum256modm[9]; + +/* see HAC, Alg. 14.42 Step 4 */ +void reduce256_modm(bignum256modm r); + +/* + Barrett reduction, see HAC, Alg. 14.42 + + Instead of passing in x, pre-process in to q1 and r1 for efficiency +*/ +void barrett_reduce256_modm(bignum256modm r, const bignum256modm q1, const bignum256modm r1); + +/* addition modulo m */ +void add256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y); + +/* -x modulo m */ +void neg256_modm(bignum256modm r, const bignum256modm x); + +/* subtraction x-y modulo m */ +void sub256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y); + +/* multiplication modulo m */ +void mul256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y); + +void expand256_modm(bignum256modm out, const unsigned char* in, size_t len); + +void expand_raw256_modm(bignum256modm out, const unsigned char in[32]); + +int is_reduced256_modm(const bignum256modm in); + +void contract256_modm(unsigned char out[32], const bignum256modm in); + +void contract256_window4_modm(signed char r[64], const bignum256modm in); + +void contract256_slidingwindow_modm(signed char r[256], const bignum256modm s, int windowsize); + +/* 64bit uint to scalar value */ +void set256_modm(bignum256modm r, uint64_t v); + +/* scalar value to 64bit uint */ +int get256_modm(uint64_t* v, const bignum256modm r); + +/* equality test on two reduced scalar values */ +int eq256_modm(const bignum256modm x, const bignum256modm y); + +/* comparison of two reduced scalar values */ +int cmp256_modm(const bignum256modm x, const bignum256modm y); + +/* scalar null check, has to be reduced */ +int iszero256_modm(const bignum256modm x); + +/* simple copy, no reduction */ +void copy256_modm(bignum256modm r, const bignum256modm x); + +/* check if nonzero && same after reduction */ +int check256_modm(const bignum256modm x); + +/* (cc - aa * bb) % l */ +void mulsub256_modm( + bignum256modm r, + const bignum256modm a, + const bignum256modm b, + const bignum256modm c); + +/* (cc + aa * bb) % l */ +void muladd256_modm( + bignum256modm r, + const bignum256modm a, + const bignum256modm b, + const bignum256modm c); diff --git a/applications/external/flipbip/lib/crypto/groestl.c b/applications/external/flipbip/lib/crypto/groestl.c new file mode 100644 index 000000000..a77da80f4 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/groestl.c @@ -0,0 +1,755 @@ +/* Groestl hash from https://github.com/Groestlcoin/vanitygen + * Trezor adaptation by Yura Pakhuchiy . */ +/* + * Groestl implementation. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @author Thomas Pornin + */ + +#include +#include + +#include "groestl_internal.h" +#include "groestl.h" +#include "memzero.h" + +#define C32e(x) \ + ((SPH_C32(x) >> 24) | ((SPH_C32(x) >> 8) & SPH_C32(0x0000FF00)) | \ + ((SPH_C32(x) << 8) & SPH_C32(0x00FF0000)) | ((SPH_C32(x) << 24) & SPH_C32(0xFF000000))) +#define dec32e_aligned sph_dec32le_aligned +#define enc32e sph_enc32le +#define B32_0(x) ((x)&0xFF) +#define B32_1(x) (((x) >> 8) & 0xFF) +#define B32_2(x) (((x) >> 16) & 0xFF) +#define B32_3(x) ((x) >> 24) + +#define R32u(u, d) SPH_T32(((u) << 16) | ((d) >> 16)) +#define R32d(u, d) SPH_T32(((u) >> 16) | ((d) << 16)) + +#define PC32up(j, r) ((sph_u32)((j) + (r))) +#define PC32dn(j, r) 0 +#define QC32up(j, r) SPH_C32(0xFFFFFFFF) +#define QC32dn(j, r) (((sph_u32)(r) << 24) ^ SPH_T32(~((sph_u32)(j) << 24))) + +#define C64e(x) \ + ((SPH_C64(x) >> 56) | ((SPH_C64(x) >> 40) & SPH_C64(0x000000000000FF00)) | \ + ((SPH_C64(x) >> 24) & SPH_C64(0x0000000000FF0000)) | \ + ((SPH_C64(x) >> 8) & SPH_C64(0x00000000FF000000)) | \ + ((SPH_C64(x) << 8) & SPH_C64(0x000000FF00000000)) | \ + ((SPH_C64(x) << 24) & SPH_C64(0x0000FF0000000000)) | \ + ((SPH_C64(x) << 40) & SPH_C64(0x00FF000000000000)) | \ + ((SPH_C64(x) << 56) & SPH_C64(0xFF00000000000000))) +#define dec64e_aligned sph_dec64le_aligned +#define enc64e sph_enc64le +#define B64_0(x) ((x)&0xFF) +#define B64_1(x) (((x) >> 8) & 0xFF) +#define B64_2(x) (((x) >> 16) & 0xFF) +#define B64_3(x) (((x) >> 24) & 0xFF) +#define B64_4(x) (((x) >> 32) & 0xFF) +#define B64_5(x) (((x) >> 40) & 0xFF) +#define B64_6(x) (((x) >> 48) & 0xFF) +#define B64_7(x) ((x) >> 56) +#define R64 SPH_ROTL64 +#define PC64(j, r) ((sph_u64)((j) + (r))) +#define QC64(j, r) (((sph_u64)(r) << 56) ^ SPH_T64(~((sph_u64)(j) << 56))) + +static const sph_u32 T0up[] = { + C32e(0xc632f4a5), C32e(0xf86f9784), C32e(0xee5eb099), C32e(0xf67a8c8d), C32e(0xffe8170d), + C32e(0xd60adcbd), C32e(0xde16c8b1), C32e(0x916dfc54), C32e(0x6090f050), C32e(0x02070503), + C32e(0xce2ee0a9), C32e(0x56d1877d), C32e(0xe7cc2b19), C32e(0xb513a662), C32e(0x4d7c31e6), + C32e(0xec59b59a), C32e(0x8f40cf45), C32e(0x1fa3bc9d), C32e(0x8949c040), C32e(0xfa689287), + C32e(0xefd03f15), C32e(0xb29426eb), C32e(0x8ece40c9), C32e(0xfbe61d0b), C32e(0x416e2fec), + C32e(0xb31aa967), C32e(0x5f431cfd), C32e(0x456025ea), C32e(0x23f9dabf), C32e(0x535102f7), + C32e(0xe445a196), C32e(0x9b76ed5b), C32e(0x75285dc2), C32e(0xe1c5241c), C32e(0x3dd4e9ae), + C32e(0x4cf2be6a), C32e(0x6c82ee5a), C32e(0x7ebdc341), C32e(0xf5f30602), C32e(0x8352d14f), + C32e(0x688ce45c), C32e(0x515607f4), C32e(0xd18d5c34), C32e(0xf9e11808), C32e(0xe24cae93), + C32e(0xab3e9573), C32e(0x6297f553), C32e(0x2a6b413f), C32e(0x081c140c), C32e(0x9563f652), + C32e(0x46e9af65), C32e(0x9d7fe25e), C32e(0x30487828), C32e(0x37cff8a1), C32e(0x0a1b110f), + C32e(0x2febc4b5), C32e(0x0e151b09), C32e(0x247e5a36), C32e(0x1badb69b), C32e(0xdf98473d), + C32e(0xcda76a26), C32e(0x4ef5bb69), C32e(0x7f334ccd), C32e(0xea50ba9f), C32e(0x123f2d1b), + C32e(0x1da4b99e), C32e(0x58c49c74), C32e(0x3446722e), C32e(0x3641772d), C32e(0xdc11cdb2), + C32e(0xb49d29ee), C32e(0x5b4d16fb), C32e(0xa4a501f6), C32e(0x76a1d74d), C32e(0xb714a361), + C32e(0x7d3449ce), C32e(0x52df8d7b), C32e(0xdd9f423e), C32e(0x5ecd9371), C32e(0x13b1a297), + C32e(0xa6a204f5), C32e(0xb901b868), C32e(0x00000000), C32e(0xc1b5742c), C32e(0x40e0a060), + C32e(0xe3c2211f), C32e(0x793a43c8), C32e(0xb69a2ced), C32e(0xd40dd9be), C32e(0x8d47ca46), + C32e(0x671770d9), C32e(0x72afdd4b), C32e(0x94ed79de), C32e(0x98ff67d4), C32e(0xb09323e8), + C32e(0x855bde4a), C32e(0xbb06bd6b), C32e(0xc5bb7e2a), C32e(0x4f7b34e5), C32e(0xedd73a16), + C32e(0x86d254c5), C32e(0x9af862d7), C32e(0x6699ff55), C32e(0x11b6a794), C32e(0x8ac04acf), + C32e(0xe9d93010), C32e(0x040e0a06), C32e(0xfe669881), C32e(0xa0ab0bf0), C32e(0x78b4cc44), + C32e(0x25f0d5ba), C32e(0x4b753ee3), C32e(0xa2ac0ef3), C32e(0x5d4419fe), C32e(0x80db5bc0), + C32e(0x0580858a), C32e(0x3fd3ecad), C32e(0x21fedfbc), C32e(0x70a8d848), C32e(0xf1fd0c04), + C32e(0x63197adf), C32e(0x772f58c1), C32e(0xaf309f75), C32e(0x42e7a563), C32e(0x20705030), + C32e(0xe5cb2e1a), C32e(0xfdef120e), C32e(0xbf08b76d), C32e(0x8155d44c), C32e(0x18243c14), + C32e(0x26795f35), C32e(0xc3b2712f), C32e(0xbe8638e1), C32e(0x35c8fda2), C32e(0x88c74fcc), + C32e(0x2e654b39), C32e(0x936af957), C32e(0x55580df2), C32e(0xfc619d82), C32e(0x7ab3c947), + C32e(0xc827efac), C32e(0xba8832e7), C32e(0x324f7d2b), C32e(0xe642a495), C32e(0xc03bfba0), + C32e(0x19aab398), C32e(0x9ef668d1), C32e(0xa322817f), C32e(0x44eeaa66), C32e(0x54d6827e), + C32e(0x3bdde6ab), C32e(0x0b959e83), C32e(0x8cc945ca), C32e(0xc7bc7b29), C32e(0x6b056ed3), + C32e(0x286c443c), C32e(0xa72c8b79), C32e(0xbc813de2), C32e(0x1631271d), C32e(0xad379a76), + C32e(0xdb964d3b), C32e(0x649efa56), C32e(0x74a6d24e), C32e(0x1436221e), C32e(0x92e476db), + C32e(0x0c121e0a), C32e(0x48fcb46c), C32e(0xb88f37e4), C32e(0x9f78e75d), C32e(0xbd0fb26e), + C32e(0x43692aef), C32e(0xc435f1a6), C32e(0x39dae3a8), C32e(0x31c6f7a4), C32e(0xd38a5937), + C32e(0xf274868b), C32e(0xd5835632), C32e(0x8b4ec543), C32e(0x6e85eb59), C32e(0xda18c2b7), + C32e(0x018e8f8c), C32e(0xb11dac64), C32e(0x9cf16dd2), C32e(0x49723be0), C32e(0xd81fc7b4), + C32e(0xacb915fa), C32e(0xf3fa0907), C32e(0xcfa06f25), C32e(0xca20eaaf), C32e(0xf47d898e), + C32e(0x476720e9), C32e(0x10382818), C32e(0x6f0b64d5), C32e(0xf0738388), C32e(0x4afbb16f), + C32e(0x5cca9672), C32e(0x38546c24), C32e(0x575f08f1), C32e(0x732152c7), C32e(0x9764f351), + C32e(0xcbae6523), C32e(0xa125847c), C32e(0xe857bf9c), C32e(0x3e5d6321), C32e(0x96ea7cdd), + C32e(0x611e7fdc), C32e(0x0d9c9186), C32e(0x0f9b9485), C32e(0xe04bab90), C32e(0x7cbac642), + C32e(0x712657c4), C32e(0xcc29e5aa), C32e(0x90e373d8), C32e(0x06090f05), C32e(0xf7f40301), + C32e(0x1c2a3612), C32e(0xc23cfea3), C32e(0x6a8be15f), C32e(0xaebe10f9), C32e(0x69026bd0), + C32e(0x17bfa891), C32e(0x9971e858), C32e(0x3a536927), C32e(0x27f7d0b9), C32e(0xd9914838), + C32e(0xebde3513), C32e(0x2be5ceb3), C32e(0x22775533), C32e(0xd204d6bb), C32e(0xa9399070), + C32e(0x07878089), C32e(0x33c1f2a7), C32e(0x2decc1b6), C32e(0x3c5a6622), C32e(0x15b8ad92), + C32e(0xc9a96020), C32e(0x875cdb49), C32e(0xaab01aff), C32e(0x50d88878), C32e(0xa52b8e7a), + C32e(0x03898a8f), C32e(0x594a13f8), C32e(0x09929b80), C32e(0x1a233917), C32e(0x651075da), + C32e(0xd7845331), C32e(0x84d551c6), C32e(0xd003d3b8), C32e(0x82dc5ec3), C32e(0x29e2cbb0), + C32e(0x5ac39977), C32e(0x1e2d3311), C32e(0x7b3d46cb), C32e(0xa8b71ffc), C32e(0x6d0c61d6), + C32e(0x2c624e3a)}; + +static const sph_u32 T0dn[] = { + C32e(0xf497a5c6), C32e(0x97eb84f8), C32e(0xb0c799ee), C32e(0x8cf78df6), C32e(0x17e50dff), + C32e(0xdcb7bdd6), C32e(0xc8a7b1de), C32e(0xfc395491), C32e(0xf0c05060), C32e(0x05040302), + C32e(0xe087a9ce), C32e(0x87ac7d56), C32e(0x2bd519e7), C32e(0xa67162b5), C32e(0x319ae64d), + C32e(0xb5c39aec), C32e(0xcf05458f), C32e(0xbc3e9d1f), C32e(0xc0094089), C32e(0x92ef87fa), + C32e(0x3fc515ef), C32e(0x267febb2), C32e(0x4007c98e), C32e(0x1ded0bfb), C32e(0x2f82ec41), + C32e(0xa97d67b3), C32e(0x1cbefd5f), C32e(0x258aea45), C32e(0xda46bf23), C32e(0x02a6f753), + C32e(0xa1d396e4), C32e(0xed2d5b9b), C32e(0x5deac275), C32e(0x24d91ce1), C32e(0xe97aae3d), + C32e(0xbe986a4c), C32e(0xeed85a6c), C32e(0xc3fc417e), C32e(0x06f102f5), C32e(0xd11d4f83), + C32e(0xe4d05c68), C32e(0x07a2f451), C32e(0x5cb934d1), C32e(0x18e908f9), C32e(0xaedf93e2), + C32e(0x954d73ab), C32e(0xf5c45362), C32e(0x41543f2a), C32e(0x14100c08), C32e(0xf6315295), + C32e(0xaf8c6546), C32e(0xe2215e9d), C32e(0x78602830), C32e(0xf86ea137), C32e(0x11140f0a), + C32e(0xc45eb52f), C32e(0x1b1c090e), C32e(0x5a483624), C32e(0xb6369b1b), C32e(0x47a53ddf), + C32e(0x6a8126cd), C32e(0xbb9c694e), C32e(0x4cfecd7f), C32e(0xbacf9fea), C32e(0x2d241b12), + C32e(0xb93a9e1d), C32e(0x9cb07458), C32e(0x72682e34), C32e(0x776c2d36), C32e(0xcda3b2dc), + C32e(0x2973eeb4), C32e(0x16b6fb5b), C32e(0x0153f6a4), C32e(0xd7ec4d76), C32e(0xa37561b7), + C32e(0x49face7d), C32e(0x8da47b52), C32e(0x42a13edd), C32e(0x93bc715e), C32e(0xa2269713), + C32e(0x0457f5a6), C32e(0xb86968b9), C32e(0x00000000), C32e(0x74992cc1), C32e(0xa0806040), + C32e(0x21dd1fe3), C32e(0x43f2c879), C32e(0x2c77edb6), C32e(0xd9b3bed4), C32e(0xca01468d), + C32e(0x70ced967), C32e(0xdde44b72), C32e(0x7933de94), C32e(0x672bd498), C32e(0x237be8b0), + C32e(0xde114a85), C32e(0xbd6d6bbb), C32e(0x7e912ac5), C32e(0x349ee54f), C32e(0x3ac116ed), + C32e(0x5417c586), C32e(0x622fd79a), C32e(0xffcc5566), C32e(0xa7229411), C32e(0x4a0fcf8a), + C32e(0x30c910e9), C32e(0x0a080604), C32e(0x98e781fe), C32e(0x0b5bf0a0), C32e(0xccf04478), + C32e(0xd54aba25), C32e(0x3e96e34b), C32e(0x0e5ff3a2), C32e(0x19bafe5d), C32e(0x5b1bc080), + C32e(0x850a8a05), C32e(0xec7ead3f), C32e(0xdf42bc21), C32e(0xd8e04870), C32e(0x0cf904f1), + C32e(0x7ac6df63), C32e(0x58eec177), C32e(0x9f4575af), C32e(0xa5846342), C32e(0x50403020), + C32e(0x2ed11ae5), C32e(0x12e10efd), C32e(0xb7656dbf), C32e(0xd4194c81), C32e(0x3c301418), + C32e(0x5f4c3526), C32e(0x719d2fc3), C32e(0x3867e1be), C32e(0xfd6aa235), C32e(0x4f0bcc88), + C32e(0x4b5c392e), C32e(0xf93d5793), C32e(0x0daaf255), C32e(0x9de382fc), C32e(0xc9f4477a), + C32e(0xef8bacc8), C32e(0x326fe7ba), C32e(0x7d642b32), C32e(0xa4d795e6), C32e(0xfb9ba0c0), + C32e(0xb3329819), C32e(0x6827d19e), C32e(0x815d7fa3), C32e(0xaa886644), C32e(0x82a87e54), + C32e(0xe676ab3b), C32e(0x9e16830b), C32e(0x4503ca8c), C32e(0x7b9529c7), C32e(0x6ed6d36b), + C32e(0x44503c28), C32e(0x8b5579a7), C32e(0x3d63e2bc), C32e(0x272c1d16), C32e(0x9a4176ad), + C32e(0x4dad3bdb), C32e(0xfac85664), C32e(0xd2e84e74), C32e(0x22281e14), C32e(0x763fdb92), + C32e(0x1e180a0c), C32e(0xb4906c48), C32e(0x376be4b8), C32e(0xe7255d9f), C32e(0xb2616ebd), + C32e(0x2a86ef43), C32e(0xf193a6c4), C32e(0xe372a839), C32e(0xf762a431), C32e(0x59bd37d3), + C32e(0x86ff8bf2), C32e(0x56b132d5), C32e(0xc50d438b), C32e(0xebdc596e), C32e(0xc2afb7da), + C32e(0x8f028c01), C32e(0xac7964b1), C32e(0x6d23d29c), C32e(0x3b92e049), C32e(0xc7abb4d8), + C32e(0x1543faac), C32e(0x09fd07f3), C32e(0x6f8525cf), C32e(0xea8fafca), C32e(0x89f38ef4), + C32e(0x208ee947), C32e(0x28201810), C32e(0x64ded56f), C32e(0x83fb88f0), C32e(0xb1946f4a), + C32e(0x96b8725c), C32e(0x6c702438), C32e(0x08aef157), C32e(0x52e6c773), C32e(0xf3355197), + C32e(0x658d23cb), C32e(0x84597ca1), C32e(0xbfcb9ce8), C32e(0x637c213e), C32e(0x7c37dd96), + C32e(0x7fc2dc61), C32e(0x911a860d), C32e(0x941e850f), C32e(0xabdb90e0), C32e(0xc6f8427c), + C32e(0x57e2c471), C32e(0xe583aacc), C32e(0x733bd890), C32e(0x0f0c0506), C32e(0x03f501f7), + C32e(0x3638121c), C32e(0xfe9fa3c2), C32e(0xe1d45f6a), C32e(0x1047f9ae), C32e(0x6bd2d069), + C32e(0xa82e9117), C32e(0xe8295899), C32e(0x6974273a), C32e(0xd04eb927), C32e(0x48a938d9), + C32e(0x35cd13eb), C32e(0xce56b32b), C32e(0x55443322), C32e(0xd6bfbbd2), C32e(0x904970a9), + C32e(0x800e8907), C32e(0xf266a733), C32e(0xc15ab62d), C32e(0x6678223c), C32e(0xad2a9215), + C32e(0x608920c9), C32e(0xdb154987), C32e(0x1a4fffaa), C32e(0x88a07850), C32e(0x8e517aa5), + C32e(0x8a068f03), C32e(0x13b2f859), C32e(0x9b128009), C32e(0x3934171a), C32e(0x75cada65), + C32e(0x53b531d7), C32e(0x5113c684), C32e(0xd3bbb8d0), C32e(0x5e1fc382), C32e(0xcb52b029), + C32e(0x99b4775a), C32e(0x333c111e), C32e(0x46f6cb7b), C32e(0x1f4bfca8), C32e(0x61dad66d), + C32e(0x4e583a2c)}; + +static const sph_u32 T1up[] = { + C32e(0xc6c632f4), C32e(0xf8f86f97), C32e(0xeeee5eb0), C32e(0xf6f67a8c), C32e(0xffffe817), + C32e(0xd6d60adc), C32e(0xdede16c8), C32e(0x91916dfc), C32e(0x606090f0), C32e(0x02020705), + C32e(0xcece2ee0), C32e(0x5656d187), C32e(0xe7e7cc2b), C32e(0xb5b513a6), C32e(0x4d4d7c31), + C32e(0xecec59b5), C32e(0x8f8f40cf), C32e(0x1f1fa3bc), C32e(0x898949c0), C32e(0xfafa6892), + C32e(0xefefd03f), C32e(0xb2b29426), C32e(0x8e8ece40), C32e(0xfbfbe61d), C32e(0x41416e2f), + C32e(0xb3b31aa9), C32e(0x5f5f431c), C32e(0x45456025), C32e(0x2323f9da), C32e(0x53535102), + C32e(0xe4e445a1), C32e(0x9b9b76ed), C32e(0x7575285d), C32e(0xe1e1c524), C32e(0x3d3dd4e9), + C32e(0x4c4cf2be), C32e(0x6c6c82ee), C32e(0x7e7ebdc3), C32e(0xf5f5f306), C32e(0x838352d1), + C32e(0x68688ce4), C32e(0x51515607), C32e(0xd1d18d5c), C32e(0xf9f9e118), C32e(0xe2e24cae), + C32e(0xabab3e95), C32e(0x626297f5), C32e(0x2a2a6b41), C32e(0x08081c14), C32e(0x959563f6), + C32e(0x4646e9af), C32e(0x9d9d7fe2), C32e(0x30304878), C32e(0x3737cff8), C32e(0x0a0a1b11), + C32e(0x2f2febc4), C32e(0x0e0e151b), C32e(0x24247e5a), C32e(0x1b1badb6), C32e(0xdfdf9847), + C32e(0xcdcda76a), C32e(0x4e4ef5bb), C32e(0x7f7f334c), C32e(0xeaea50ba), C32e(0x12123f2d), + C32e(0x1d1da4b9), C32e(0x5858c49c), C32e(0x34344672), C32e(0x36364177), C32e(0xdcdc11cd), + C32e(0xb4b49d29), C32e(0x5b5b4d16), C32e(0xa4a4a501), C32e(0x7676a1d7), C32e(0xb7b714a3), + C32e(0x7d7d3449), C32e(0x5252df8d), C32e(0xdddd9f42), C32e(0x5e5ecd93), C32e(0x1313b1a2), + C32e(0xa6a6a204), C32e(0xb9b901b8), C32e(0x00000000), C32e(0xc1c1b574), C32e(0x4040e0a0), + C32e(0xe3e3c221), C32e(0x79793a43), C32e(0xb6b69a2c), C32e(0xd4d40dd9), C32e(0x8d8d47ca), + C32e(0x67671770), C32e(0x7272afdd), C32e(0x9494ed79), C32e(0x9898ff67), C32e(0xb0b09323), + C32e(0x85855bde), C32e(0xbbbb06bd), C32e(0xc5c5bb7e), C32e(0x4f4f7b34), C32e(0xededd73a), + C32e(0x8686d254), C32e(0x9a9af862), C32e(0x666699ff), C32e(0x1111b6a7), C32e(0x8a8ac04a), + C32e(0xe9e9d930), C32e(0x04040e0a), C32e(0xfefe6698), C32e(0xa0a0ab0b), C32e(0x7878b4cc), + C32e(0x2525f0d5), C32e(0x4b4b753e), C32e(0xa2a2ac0e), C32e(0x5d5d4419), C32e(0x8080db5b), + C32e(0x05058085), C32e(0x3f3fd3ec), C32e(0x2121fedf), C32e(0x7070a8d8), C32e(0xf1f1fd0c), + C32e(0x6363197a), C32e(0x77772f58), C32e(0xafaf309f), C32e(0x4242e7a5), C32e(0x20207050), + C32e(0xe5e5cb2e), C32e(0xfdfdef12), C32e(0xbfbf08b7), C32e(0x818155d4), C32e(0x1818243c), + C32e(0x2626795f), C32e(0xc3c3b271), C32e(0xbebe8638), C32e(0x3535c8fd), C32e(0x8888c74f), + C32e(0x2e2e654b), C32e(0x93936af9), C32e(0x5555580d), C32e(0xfcfc619d), C32e(0x7a7ab3c9), + C32e(0xc8c827ef), C32e(0xbaba8832), C32e(0x32324f7d), C32e(0xe6e642a4), C32e(0xc0c03bfb), + C32e(0x1919aab3), C32e(0x9e9ef668), C32e(0xa3a32281), C32e(0x4444eeaa), C32e(0x5454d682), + C32e(0x3b3bdde6), C32e(0x0b0b959e), C32e(0x8c8cc945), C32e(0xc7c7bc7b), C32e(0x6b6b056e), + C32e(0x28286c44), C32e(0xa7a72c8b), C32e(0xbcbc813d), C32e(0x16163127), C32e(0xadad379a), + C32e(0xdbdb964d), C32e(0x64649efa), C32e(0x7474a6d2), C32e(0x14143622), C32e(0x9292e476), + C32e(0x0c0c121e), C32e(0x4848fcb4), C32e(0xb8b88f37), C32e(0x9f9f78e7), C32e(0xbdbd0fb2), + C32e(0x4343692a), C32e(0xc4c435f1), C32e(0x3939dae3), C32e(0x3131c6f7), C32e(0xd3d38a59), + C32e(0xf2f27486), C32e(0xd5d58356), C32e(0x8b8b4ec5), C32e(0x6e6e85eb), C32e(0xdada18c2), + C32e(0x01018e8f), C32e(0xb1b11dac), C32e(0x9c9cf16d), C32e(0x4949723b), C32e(0xd8d81fc7), + C32e(0xacacb915), C32e(0xf3f3fa09), C32e(0xcfcfa06f), C32e(0xcaca20ea), C32e(0xf4f47d89), + C32e(0x47476720), C32e(0x10103828), C32e(0x6f6f0b64), C32e(0xf0f07383), C32e(0x4a4afbb1), + C32e(0x5c5cca96), C32e(0x3838546c), C32e(0x57575f08), C32e(0x73732152), C32e(0x979764f3), + C32e(0xcbcbae65), C32e(0xa1a12584), C32e(0xe8e857bf), C32e(0x3e3e5d63), C32e(0x9696ea7c), + C32e(0x61611e7f), C32e(0x0d0d9c91), C32e(0x0f0f9b94), C32e(0xe0e04bab), C32e(0x7c7cbac6), + C32e(0x71712657), C32e(0xcccc29e5), C32e(0x9090e373), C32e(0x0606090f), C32e(0xf7f7f403), + C32e(0x1c1c2a36), C32e(0xc2c23cfe), C32e(0x6a6a8be1), C32e(0xaeaebe10), C32e(0x6969026b), + C32e(0x1717bfa8), C32e(0x999971e8), C32e(0x3a3a5369), C32e(0x2727f7d0), C32e(0xd9d99148), + C32e(0xebebde35), C32e(0x2b2be5ce), C32e(0x22227755), C32e(0xd2d204d6), C32e(0xa9a93990), + C32e(0x07078780), C32e(0x3333c1f2), C32e(0x2d2decc1), C32e(0x3c3c5a66), C32e(0x1515b8ad), + C32e(0xc9c9a960), C32e(0x87875cdb), C32e(0xaaaab01a), C32e(0x5050d888), C32e(0xa5a52b8e), + C32e(0x0303898a), C32e(0x59594a13), C32e(0x0909929b), C32e(0x1a1a2339), C32e(0x65651075), + C32e(0xd7d78453), C32e(0x8484d551), C32e(0xd0d003d3), C32e(0x8282dc5e), C32e(0x2929e2cb), + C32e(0x5a5ac399), C32e(0x1e1e2d33), C32e(0x7b7b3d46), C32e(0xa8a8b71f), C32e(0x6d6d0c61), + C32e(0x2c2c624e)}; + +static const sph_u32 T1dn[] = { + C32e(0xa5f497a5), C32e(0x8497eb84), C32e(0x99b0c799), C32e(0x8d8cf78d), C32e(0x0d17e50d), + C32e(0xbddcb7bd), C32e(0xb1c8a7b1), C32e(0x54fc3954), C32e(0x50f0c050), C32e(0x03050403), + C32e(0xa9e087a9), C32e(0x7d87ac7d), C32e(0x192bd519), C32e(0x62a67162), C32e(0xe6319ae6), + C32e(0x9ab5c39a), C32e(0x45cf0545), C32e(0x9dbc3e9d), C32e(0x40c00940), C32e(0x8792ef87), + C32e(0x153fc515), C32e(0xeb267feb), C32e(0xc94007c9), C32e(0x0b1ded0b), C32e(0xec2f82ec), + C32e(0x67a97d67), C32e(0xfd1cbefd), C32e(0xea258aea), C32e(0xbfda46bf), C32e(0xf702a6f7), + C32e(0x96a1d396), C32e(0x5bed2d5b), C32e(0xc25deac2), C32e(0x1c24d91c), C32e(0xaee97aae), + C32e(0x6abe986a), C32e(0x5aeed85a), C32e(0x41c3fc41), C32e(0x0206f102), C32e(0x4fd11d4f), + C32e(0x5ce4d05c), C32e(0xf407a2f4), C32e(0x345cb934), C32e(0x0818e908), C32e(0x93aedf93), + C32e(0x73954d73), C32e(0x53f5c453), C32e(0x3f41543f), C32e(0x0c14100c), C32e(0x52f63152), + C32e(0x65af8c65), C32e(0x5ee2215e), C32e(0x28786028), C32e(0xa1f86ea1), C32e(0x0f11140f), + C32e(0xb5c45eb5), C32e(0x091b1c09), C32e(0x365a4836), C32e(0x9bb6369b), C32e(0x3d47a53d), + C32e(0x266a8126), C32e(0x69bb9c69), C32e(0xcd4cfecd), C32e(0x9fbacf9f), C32e(0x1b2d241b), + C32e(0x9eb93a9e), C32e(0x749cb074), C32e(0x2e72682e), C32e(0x2d776c2d), C32e(0xb2cda3b2), + C32e(0xee2973ee), C32e(0xfb16b6fb), C32e(0xf60153f6), C32e(0x4dd7ec4d), C32e(0x61a37561), + C32e(0xce49face), C32e(0x7b8da47b), C32e(0x3e42a13e), C32e(0x7193bc71), C32e(0x97a22697), + C32e(0xf50457f5), C32e(0x68b86968), C32e(0x00000000), C32e(0x2c74992c), C32e(0x60a08060), + C32e(0x1f21dd1f), C32e(0xc843f2c8), C32e(0xed2c77ed), C32e(0xbed9b3be), C32e(0x46ca0146), + C32e(0xd970ced9), C32e(0x4bdde44b), C32e(0xde7933de), C32e(0xd4672bd4), C32e(0xe8237be8), + C32e(0x4ade114a), C32e(0x6bbd6d6b), C32e(0x2a7e912a), C32e(0xe5349ee5), C32e(0x163ac116), + C32e(0xc55417c5), C32e(0xd7622fd7), C32e(0x55ffcc55), C32e(0x94a72294), C32e(0xcf4a0fcf), + C32e(0x1030c910), C32e(0x060a0806), C32e(0x8198e781), C32e(0xf00b5bf0), C32e(0x44ccf044), + C32e(0xbad54aba), C32e(0xe33e96e3), C32e(0xf30e5ff3), C32e(0xfe19bafe), C32e(0xc05b1bc0), + C32e(0x8a850a8a), C32e(0xadec7ead), C32e(0xbcdf42bc), C32e(0x48d8e048), C32e(0x040cf904), + C32e(0xdf7ac6df), C32e(0xc158eec1), C32e(0x759f4575), C32e(0x63a58463), C32e(0x30504030), + C32e(0x1a2ed11a), C32e(0x0e12e10e), C32e(0x6db7656d), C32e(0x4cd4194c), C32e(0x143c3014), + C32e(0x355f4c35), C32e(0x2f719d2f), C32e(0xe13867e1), C32e(0xa2fd6aa2), C32e(0xcc4f0bcc), + C32e(0x394b5c39), C32e(0x57f93d57), C32e(0xf20daaf2), C32e(0x829de382), C32e(0x47c9f447), + C32e(0xacef8bac), C32e(0xe7326fe7), C32e(0x2b7d642b), C32e(0x95a4d795), C32e(0xa0fb9ba0), + C32e(0x98b33298), C32e(0xd16827d1), C32e(0x7f815d7f), C32e(0x66aa8866), C32e(0x7e82a87e), + C32e(0xabe676ab), C32e(0x839e1683), C32e(0xca4503ca), C32e(0x297b9529), C32e(0xd36ed6d3), + C32e(0x3c44503c), C32e(0x798b5579), C32e(0xe23d63e2), C32e(0x1d272c1d), C32e(0x769a4176), + C32e(0x3b4dad3b), C32e(0x56fac856), C32e(0x4ed2e84e), C32e(0x1e22281e), C32e(0xdb763fdb), + C32e(0x0a1e180a), C32e(0x6cb4906c), C32e(0xe4376be4), C32e(0x5de7255d), C32e(0x6eb2616e), + C32e(0xef2a86ef), C32e(0xa6f193a6), C32e(0xa8e372a8), C32e(0xa4f762a4), C32e(0x3759bd37), + C32e(0x8b86ff8b), C32e(0x3256b132), C32e(0x43c50d43), C32e(0x59ebdc59), C32e(0xb7c2afb7), + C32e(0x8c8f028c), C32e(0x64ac7964), C32e(0xd26d23d2), C32e(0xe03b92e0), C32e(0xb4c7abb4), + C32e(0xfa1543fa), C32e(0x0709fd07), C32e(0x256f8525), C32e(0xafea8faf), C32e(0x8e89f38e), + C32e(0xe9208ee9), C32e(0x18282018), C32e(0xd564ded5), C32e(0x8883fb88), C32e(0x6fb1946f), + C32e(0x7296b872), C32e(0x246c7024), C32e(0xf108aef1), C32e(0xc752e6c7), C32e(0x51f33551), + C32e(0x23658d23), C32e(0x7c84597c), C32e(0x9cbfcb9c), C32e(0x21637c21), C32e(0xdd7c37dd), + C32e(0xdc7fc2dc), C32e(0x86911a86), C32e(0x85941e85), C32e(0x90abdb90), C32e(0x42c6f842), + C32e(0xc457e2c4), C32e(0xaae583aa), C32e(0xd8733bd8), C32e(0x050f0c05), C32e(0x0103f501), + C32e(0x12363812), C32e(0xa3fe9fa3), C32e(0x5fe1d45f), C32e(0xf91047f9), C32e(0xd06bd2d0), + C32e(0x91a82e91), C32e(0x58e82958), C32e(0x27697427), C32e(0xb9d04eb9), C32e(0x3848a938), + C32e(0x1335cd13), C32e(0xb3ce56b3), C32e(0x33554433), C32e(0xbbd6bfbb), C32e(0x70904970), + C32e(0x89800e89), C32e(0xa7f266a7), C32e(0xb6c15ab6), C32e(0x22667822), C32e(0x92ad2a92), + C32e(0x20608920), C32e(0x49db1549), C32e(0xff1a4fff), C32e(0x7888a078), C32e(0x7a8e517a), + C32e(0x8f8a068f), C32e(0xf813b2f8), C32e(0x809b1280), C32e(0x17393417), C32e(0xda75cada), + C32e(0x3153b531), C32e(0xc65113c6), C32e(0xb8d3bbb8), C32e(0xc35e1fc3), C32e(0xb0cb52b0), + C32e(0x7799b477), C32e(0x11333c11), C32e(0xcb46f6cb), C32e(0xfc1f4bfc), C32e(0xd661dad6), + C32e(0x3a4e583a)}; + +#define DECL_STATE_SMALL sph_u32 H[16] = {0}; + +#define READ_STATE_SMALL(sc) \ + do { \ + memcpy(H, (sc)->state.narrow, sizeof H); \ + } while(0) + +#define WRITE_STATE_SMALL(sc) \ + do { \ + memcpy((sc)->state.narrow, H, sizeof H); \ + } while(0) + +#define XCAT(x, y) XCAT_(x, y) +#define XCAT_(x, y) x##y + +#define RSTT(d0, d1, a, b0, b1, b2, b3, b4, b5, b6, b7) \ + do { \ + t[d0] = T0up[B32_0(a[b0])] ^ T1up[B32_1(a[b1])] ^ T2up[B32_2(a[b2])] ^ \ + T3up[B32_3(a[b3])] ^ T0dn[B32_0(a[b4])] ^ T1dn[B32_1(a[b5])] ^ \ + T2dn[B32_2(a[b6])] ^ T3dn[B32_3(a[b7])]; \ + t[d1] = T0dn[B32_0(a[b0])] ^ T1dn[B32_1(a[b1])] ^ T2dn[B32_2(a[b2])] ^ \ + T3dn[B32_3(a[b3])] ^ T0up[B32_0(a[b4])] ^ T1up[B32_1(a[b5])] ^ \ + T2up[B32_2(a[b6])] ^ T3up[B32_3(a[b7])]; \ + } while(0) + +#define ROUND_SMALL_P(a, r) \ + do { \ + sph_u32 t[16]; \ + a[0x0] ^= PC32up(0x00, r); \ + a[0x1] ^= PC32dn(0x00, r); \ + a[0x2] ^= PC32up(0x10, r); \ + a[0x3] ^= PC32dn(0x10, r); \ + a[0x4] ^= PC32up(0x20, r); \ + a[0x5] ^= PC32dn(0x20, r); \ + a[0x6] ^= PC32up(0x30, r); \ + a[0x7] ^= PC32dn(0x30, r); \ + a[0x8] ^= PC32up(0x40, r); \ + a[0x9] ^= PC32dn(0x40, r); \ + a[0xA] ^= PC32up(0x50, r); \ + a[0xB] ^= PC32dn(0x50, r); \ + a[0xC] ^= PC32up(0x60, r); \ + a[0xD] ^= PC32dn(0x60, r); \ + a[0xE] ^= PC32up(0x70, r); \ + a[0xF] ^= PC32dn(0x70, r); \ + RSTT(0x0, 0x1, a, 0x0, 0x2, 0x4, 0x6, 0x9, 0xB, 0xD, 0xF); \ + RSTT(0x2, 0x3, a, 0x2, 0x4, 0x6, 0x8, 0xB, 0xD, 0xF, 0x1); \ + RSTT(0x4, 0x5, a, 0x4, 0x6, 0x8, 0xA, 0xD, 0xF, 0x1, 0x3); \ + RSTT(0x6, 0x7, a, 0x6, 0x8, 0xA, 0xC, 0xF, 0x1, 0x3, 0x5); \ + RSTT(0x8, 0x9, a, 0x8, 0xA, 0xC, 0xE, 0x1, 0x3, 0x5, 0x7); \ + RSTT(0xA, 0xB, a, 0xA, 0xC, 0xE, 0x0, 0x3, 0x5, 0x7, 0x9); \ + RSTT(0xC, 0xD, a, 0xC, 0xE, 0x0, 0x2, 0x5, 0x7, 0x9, 0xB); \ + RSTT(0xE, 0xF, a, 0xE, 0x0, 0x2, 0x4, 0x7, 0x9, 0xB, 0xD); \ + memcpy(a, t, sizeof t); \ + } while(0) + +#define ROUND_SMALL_Q(a, r) \ + do { \ + sph_u32 t[16]; \ + a[0x0] ^= QC32up(0x00, r); \ + a[0x1] ^= QC32dn(0x00, r); \ + a[0x2] ^= QC32up(0x10, r); \ + a[0x3] ^= QC32dn(0x10, r); \ + a[0x4] ^= QC32up(0x20, r); \ + a[0x5] ^= QC32dn(0x20, r); \ + a[0x6] ^= QC32up(0x30, r); \ + a[0x7] ^= QC32dn(0x30, r); \ + a[0x8] ^= QC32up(0x40, r); \ + a[0x9] ^= QC32dn(0x40, r); \ + a[0xA] ^= QC32up(0x50, r); \ + a[0xB] ^= QC32dn(0x50, r); \ + a[0xC] ^= QC32up(0x60, r); \ + a[0xD] ^= QC32dn(0x60, r); \ + a[0xE] ^= QC32up(0x70, r); \ + a[0xF] ^= QC32dn(0x70, r); \ + RSTT(0x0, 0x1, a, 0x2, 0x6, 0xA, 0xE, 0x1, 0x5, 0x9, 0xD); \ + RSTT(0x2, 0x3, a, 0x4, 0x8, 0xC, 0x0, 0x3, 0x7, 0xB, 0xF); \ + RSTT(0x4, 0x5, a, 0x6, 0xA, 0xE, 0x2, 0x5, 0x9, 0xD, 0x1); \ + RSTT(0x6, 0x7, a, 0x8, 0xC, 0x0, 0x4, 0x7, 0xB, 0xF, 0x3); \ + RSTT(0x8, 0x9, a, 0xA, 0xE, 0x2, 0x6, 0x9, 0xD, 0x1, 0x5); \ + RSTT(0xA, 0xB, a, 0xC, 0x0, 0x4, 0x8, 0xB, 0xF, 0x3, 0x7); \ + RSTT(0xC, 0xD, a, 0xE, 0x2, 0x6, 0xA, 0xD, 0x1, 0x5, 0x9); \ + RSTT(0xE, 0xF, a, 0x0, 0x4, 0x8, 0xC, 0xF, 0x3, 0x7, 0xB); \ + memcpy(a, t, sizeof t); \ + } while(0) + +#define PERM_SMALL_P(a) \ + do { \ + int r; \ + for(r = 0; r < 10; r++) ROUND_SMALL_P(a, r); \ + } while(0) + +#define PERM_SMALL_Q(a) \ + do { \ + int r; \ + for(r = 0; r < 10; r++) ROUND_SMALL_Q(a, r); \ + } while(0) + +#define COMPRESS_SMALL \ + do { \ + sph_u32 g[16], m[16]; \ + size_t u; \ + for(u = 0; u < 16; u++) { \ + m[u] = dec32e_aligned(buf + (u << 2)); \ + g[u] = m[u] ^ H[u]; \ + } \ + PERM_SMALL_P(g); \ + PERM_SMALL_Q(m); \ + for(u = 0; u < 16; u++) H[u] ^= g[u] ^ m[u]; \ + } while(0) + +#define FINAL_SMALL \ + do { \ + sph_u32 x[16]; \ + size_t u; \ + memcpy(x, H, sizeof x); \ + PERM_SMALL_P(x); \ + for(u = 0; u < 16; u++) H[u] ^= x[u]; \ + } while(0) + +#define DECL_STATE_BIG sph_u32 H[32] = {0}; + +#define READ_STATE_BIG(sc) \ + do { \ + memcpy(H, (sc)->state.narrow, sizeof H); \ + } while(0) + +#define WRITE_STATE_BIG(sc) \ + do { \ + memcpy((sc)->state.narrow, H, sizeof H); \ + } while(0) + +#define RBTT(d0, d1, a, b0, b1, b2, b3, b4, b5, b6, b7) \ + do { \ + sph_u32 fu2 = T0up[B32_2(a[b2])]; \ + sph_u32 fd2 = T0dn[B32_2(a[b2])]; \ + sph_u32 fu3 = T1up[B32_3(a[b3])]; \ + sph_u32 fd3 = T1dn[B32_3(a[b3])]; \ + sph_u32 fu6 = T0up[B32_2(a[b6])]; \ + sph_u32 fd6 = T0dn[B32_2(a[b6])]; \ + sph_u32 fu7 = T1up[B32_3(a[b7])]; \ + sph_u32 fd7 = T1dn[B32_3(a[b7])]; \ + t[d0] = T0up[B32_0(a[b0])] ^ T1up[B32_1(a[b1])] ^ R32u(fu2, fd2) ^ R32u(fu3, fd3) ^ \ + T0dn[B32_0(a[b4])] ^ T1dn[B32_1(a[b5])] ^ R32d(fu6, fd6) ^ R32d(fu7, fd7); \ + t[d1] = T0dn[B32_0(a[b0])] ^ T1dn[B32_1(a[b1])] ^ R32d(fu2, fd2) ^ R32d(fu3, fd3) ^ \ + T0up[B32_0(a[b4])] ^ T1up[B32_1(a[b5])] ^ R32u(fu6, fd6) ^ R32u(fu7, fd7); \ + } while(0) + +#define ROUND_BIG_P(a, r) \ + do { \ + sph_u32 t[32]; \ + size_t u; \ + a[0x00] ^= PC32up(0x00, r); \ + a[0x01] ^= PC32dn(0x00, r); \ + a[0x02] ^= PC32up(0x10, r); \ + a[0x03] ^= PC32dn(0x10, r); \ + a[0x04] ^= PC32up(0x20, r); \ + a[0x05] ^= PC32dn(0x20, r); \ + a[0x06] ^= PC32up(0x30, r); \ + a[0x07] ^= PC32dn(0x30, r); \ + a[0x08] ^= PC32up(0x40, r); \ + a[0x09] ^= PC32dn(0x40, r); \ + a[0x0A] ^= PC32up(0x50, r); \ + a[0x0B] ^= PC32dn(0x50, r); \ + a[0x0C] ^= PC32up(0x60, r); \ + a[0x0D] ^= PC32dn(0x60, r); \ + a[0x0E] ^= PC32up(0x70, r); \ + a[0x0F] ^= PC32dn(0x70, r); \ + a[0x10] ^= PC32up(0x80, r); \ + a[0x11] ^= PC32dn(0x80, r); \ + a[0x12] ^= PC32up(0x90, r); \ + a[0x13] ^= PC32dn(0x90, r); \ + a[0x14] ^= PC32up(0xA0, r); \ + a[0x15] ^= PC32dn(0xA0, r); \ + a[0x16] ^= PC32up(0xB0, r); \ + a[0x17] ^= PC32dn(0xB0, r); \ + a[0x18] ^= PC32up(0xC0, r); \ + a[0x19] ^= PC32dn(0xC0, r); \ + a[0x1A] ^= PC32up(0xD0, r); \ + a[0x1B] ^= PC32dn(0xD0, r); \ + a[0x1C] ^= PC32up(0xE0, r); \ + a[0x1D] ^= PC32dn(0xE0, r); \ + a[0x1E] ^= PC32up(0xF0, r); \ + a[0x1F] ^= PC32dn(0xF0, r); \ + for(u = 0; u < 32; u += 8) { \ + RBTT( \ + u + 0x00, \ + (u + 0x01) & 0x1F, \ + a, \ + u + 0x00, \ + (u + 0x02) & 0x1F, \ + (u + 0x04) & 0x1F, \ + (u + 0x06) & 0x1F, \ + (u + 0x09) & 0x1F, \ + (u + 0x0B) & 0x1F, \ + (u + 0x0D) & 0x1F, \ + (u + 0x17) & 0x1F); \ + RBTT( \ + u + 0x02, \ + (u + 0x03) & 0x1F, \ + a, \ + u + 0x02, \ + (u + 0x04) & 0x1F, \ + (u + 0x06) & 0x1F, \ + (u + 0x08) & 0x1F, \ + (u + 0x0B) & 0x1F, \ + (u + 0x0D) & 0x1F, \ + (u + 0x0F) & 0x1F, \ + (u + 0x19) & 0x1F); \ + RBTT( \ + u + 0x04, \ + (u + 0x05) & 0x1F, \ + a, \ + u + 0x04, \ + (u + 0x06) & 0x1F, \ + (u + 0x08) & 0x1F, \ + (u + 0x0A) & 0x1F, \ + (u + 0x0D) & 0x1F, \ + (u + 0x0F) & 0x1F, \ + (u + 0x11) & 0x1F, \ + (u + 0x1B) & 0x1F); \ + RBTT( \ + u + 0x06, \ + (u + 0x07) & 0x1F, \ + a, \ + u + 0x06, \ + (u + 0x08) & 0x1F, \ + (u + 0x0A) & 0x1F, \ + (u + 0x0C) & 0x1F, \ + (u + 0x0F) & 0x1F, \ + (u + 0x11) & 0x1F, \ + (u + 0x13) & 0x1F, \ + (u + 0x1D) & 0x1F); \ + } \ + memcpy(a, t, sizeof t); \ + } while(0) + +#define ROUND_BIG_Q(a, r) \ + do { \ + sph_u32 t[32]; \ + size_t u; \ + a[0x00] ^= QC32up(0x00, r); \ + a[0x01] ^= QC32dn(0x00, r); \ + a[0x02] ^= QC32up(0x10, r); \ + a[0x03] ^= QC32dn(0x10, r); \ + a[0x04] ^= QC32up(0x20, r); \ + a[0x05] ^= QC32dn(0x20, r); \ + a[0x06] ^= QC32up(0x30, r); \ + a[0x07] ^= QC32dn(0x30, r); \ + a[0x08] ^= QC32up(0x40, r); \ + a[0x09] ^= QC32dn(0x40, r); \ + a[0x0A] ^= QC32up(0x50, r); \ + a[0x0B] ^= QC32dn(0x50, r); \ + a[0x0C] ^= QC32up(0x60, r); \ + a[0x0D] ^= QC32dn(0x60, r); \ + a[0x0E] ^= QC32up(0x70, r); \ + a[0x0F] ^= QC32dn(0x70, r); \ + a[0x10] ^= QC32up(0x80, r); \ + a[0x11] ^= QC32dn(0x80, r); \ + a[0x12] ^= QC32up(0x90, r); \ + a[0x13] ^= QC32dn(0x90, r); \ + a[0x14] ^= QC32up(0xA0, r); \ + a[0x15] ^= QC32dn(0xA0, r); \ + a[0x16] ^= QC32up(0xB0, r); \ + a[0x17] ^= QC32dn(0xB0, r); \ + a[0x18] ^= QC32up(0xC0, r); \ + a[0x19] ^= QC32dn(0xC0, r); \ + a[0x1A] ^= QC32up(0xD0, r); \ + a[0x1B] ^= QC32dn(0xD0, r); \ + a[0x1C] ^= QC32up(0xE0, r); \ + a[0x1D] ^= QC32dn(0xE0, r); \ + a[0x1E] ^= QC32up(0xF0, r); \ + a[0x1F] ^= QC32dn(0xF0, r); \ + for(u = 0; u < 32; u += 8) { \ + RBTT( \ + u + 0x00, \ + (u + 0x01) & 0x1F, \ + a, \ + (u + 0x02) & 0x1F, \ + (u + 0x06) & 0x1F, \ + (u + 0x0A) & 0x1F, \ + (u + 0x16) & 0x1F, \ + (u + 0x01) & 0x1F, \ + (u + 0x05) & 0x1F, \ + (u + 0x09) & 0x1F, \ + (u + 0x0D) & 0x1F); \ + RBTT( \ + u + 0x02, \ + (u + 0x03) & 0x1F, \ + a, \ + (u + 0x04) & 0x1F, \ + (u + 0x08) & 0x1F, \ + (u + 0x0C) & 0x1F, \ + (u + 0x18) & 0x1F, \ + (u + 0x03) & 0x1F, \ + (u + 0x07) & 0x1F, \ + (u + 0x0B) & 0x1F, \ + (u + 0x0F) & 0x1F); \ + RBTT( \ + u + 0x04, \ + (u + 0x05) & 0x1F, \ + a, \ + (u + 0x06) & 0x1F, \ + (u + 0x0A) & 0x1F, \ + (u + 0x0E) & 0x1F, \ + (u + 0x1A) & 0x1F, \ + (u + 0x05) & 0x1F, \ + (u + 0x09) & 0x1F, \ + (u + 0x0D) & 0x1F, \ + (u + 0x11) & 0x1F); \ + RBTT( \ + u + 0x06, \ + (u + 0x07) & 0x1F, \ + a, \ + (u + 0x08) & 0x1F, \ + (u + 0x0C) & 0x1F, \ + (u + 0x10) & 0x1F, \ + (u + 0x1C) & 0x1F, \ + (u + 0x07) & 0x1F, \ + (u + 0x0B) & 0x1F, \ + (u + 0x0F) & 0x1F, \ + (u + 0x13) & 0x1F); \ + } \ + memcpy(a, t, sizeof t); \ + } while(0) + +#define PERM_BIG_P(a) \ + do { \ + int r; \ + for(r = 0; r < 14; r++) ROUND_BIG_P(a, r); \ + } while(0) + +#define PERM_BIG_Q(a) \ + do { \ + int r; \ + for(r = 0; r < 14; r++) ROUND_BIG_Q(a, r); \ + } while(0) + +#define COMPRESS_BIG \ + do { \ + sph_u32 g[32], m[32]; \ + size_t uu; \ + for(uu = 0; uu < 32; uu++) { \ + m[uu] = dec32e_aligned(buf + (uu << 2)); \ + g[uu] = m[uu] ^ H[uu]; \ + } \ + PERM_BIG_P(g); \ + PERM_BIG_Q(m); \ + for(uu = 0; uu < 32; uu++) H[uu] ^= g[uu] ^ m[uu]; \ + } while(0) + +#define FINAL_BIG \ + do { \ + sph_u32 x[32]; \ + size_t uu; \ + memcpy(x, H, sizeof x); \ + PERM_BIG_P(x); \ + for(uu = 0; uu < 32; uu++) H[uu] ^= x[uu]; \ + } while(0) + +static void groestl_big_init(sph_groestl_big_context* sc, unsigned out_size) { + size_t u = 0; + + sc->ptr = 0; + for(u = 0; u < 31; u++) sc->state.narrow[u] = 0; + sc->state.narrow[31] = ((sph_u32)(out_size & 0xFF) << 24) | + ((sph_u32)(out_size & 0xFF00) << 8); + sc->count = 0; +} + +static void groestl_big_core(sph_groestl_big_context* sc, const void* data, size_t len) { + if(len == 0) { + return; + } + + unsigned char* buf = NULL; + size_t ptr = 0; + DECL_STATE_BIG + + buf = sc->buf; + ptr = sc->ptr; + if(len < (sizeof sc->buf) - ptr) { + memcpy(buf + ptr, data, len); + ptr += len; + sc->ptr = ptr; + return; + } + + READ_STATE_BIG(sc); + while(len > 0) { + size_t clen = 0; + + clen = (sizeof sc->buf) - ptr; + if(clen > len) clen = len; + memcpy(buf + ptr, data, clen); + ptr += clen; + data = (const unsigned char*)data + clen; + len -= clen; + if(ptr == sizeof sc->buf) { + COMPRESS_BIG; + sc->count++; + ptr = 0; + } + } + WRITE_STATE_BIG(sc); + sc->ptr = ptr; +} + +static void groestl_big_close( + sph_groestl_big_context* sc, + unsigned ub, + unsigned n, + void* dst, + size_t out_len) { + unsigned char pad[136] = {0}; + size_t ptr = 0, pad_len = 0, u2 = 0; + sph_u64 count = 0; + unsigned z = 0; + DECL_STATE_BIG + + ptr = sc->ptr; + z = 0x80 >> n; + pad[0] = ((ub & -z) | z) & 0xFF; + if(ptr < 120) { + pad_len = 128 - ptr; + count = SPH_T64(sc->count + 1); + } else { + pad_len = 256 - ptr; + count = SPH_T64(sc->count + 2); + } + memzero(pad + 1, pad_len - 9); + sph_enc64be(pad + pad_len - 8, count); + groestl_big_core(sc, pad, pad_len); + READ_STATE_BIG(sc); + FINAL_BIG; + for(u2 = 0; u2 < 16; u2++) enc32e(pad + (u2 << 2), H[u2 + 16]); + memcpy(dst, pad + 64 - out_len, out_len); + groestl_big_init(sc, (unsigned)out_len << 3); +} + +void groestl512_Init(void* cc) { + groestl_big_init((sph_groestl_big_context*)cc, 512); +} + +void groestl512_Update(void* cc, const void* data, size_t len) { + groestl_big_core((sph_groestl_big_context*)cc, data, len); +} + +void groestl512_Final(void* cc, void* dst) { + groestl_big_close((sph_groestl_big_context*)cc, 0, 0, dst, 64); +} + +void groestl512_DoubleTrunc(void* cc, void* dst) { + char buf[64] = {0}; + + groestl512_Final(cc, buf); + groestl512_Update(cc, buf, sizeof(buf)); + groestl512_Final(cc, buf); + memcpy(dst, buf, 32); +} diff --git a/applications/external/flipbip/lib/crypto/groestl.h b/applications/external/flipbip/lib/crypto/groestl.h new file mode 100644 index 000000000..a4871deff --- /dev/null +++ b/applications/external/flipbip/lib/crypto/groestl.h @@ -0,0 +1,95 @@ +/* Groestl hash from https://github.com/Groestlcoin/vanitygen + * Trezor adaptation by Yura Pakhuchiy . */ +/** + * Groestl interface. This code implements Groestl with the recommended + * parameters for SHA-3, with outputs of 224, 256, 384 and 512 bits. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @file sph_groestl.h + * @author Thomas Pornin + */ + +#ifndef GROESTL_H__ +#define GROESTL_H__ + +#include + +/** + * This structure is a context for Groestl-384 and Groestl-512 computations: + * it contains the intermediate values and some data from the last + * entered block. Once a Groestl computation has been performed, the + * context can be reused for another computation. + * + * The contents of this structure are private. A running Groestl + * computation can be cloned by copying the context (e.g. with a simple + * memcpy()). + */ +typedef struct { + unsigned char buf[128]; /* first field, for alignment */ + size_t ptr; + union { + uint64_t wide[16]; + uint32_t narrow[32]; + } state; + uint64_t count; +} sph_groestl_big_context; + +typedef sph_groestl_big_context GROESTL512_CTX; + +/** + * Initialize a Groestl-512 context. This process performs no memory allocation. + * + * @param cc the Groestl-512 context (pointer to a + * GROESTL512_CTX) + */ +void groestl512_Init(void* cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the Groestl-512 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void groestl512_Update(void* cc, const void* data, size_t len); + +/** + * Terminate the current Groestl-512 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (64 bytes). The context is automatically + * reinitialized. + * + * @param cc the Groestl-512 context + * @param dst the destination buffer + */ +void groestl512_Final(void* cc, void* dst); + +/* Calculate double Groestl-512 hash and truncate it to 256-bits. */ +void groestl512_DoubleTrunc(void* cc, void* dst); + +#endif diff --git a/applications/external/flipbip/lib/crypto/groestl_internal.h b/applications/external/flipbip/lib/crypto/groestl_internal.h new file mode 100644 index 000000000..3859ff532 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/groestl_internal.h @@ -0,0 +1,461 @@ +/* Groestl hash from https://github.com/Groestlcoin/vanitygen + * Trezor adaptation by Yura Pakhuchiy . */ +/** + * Basic type definitions. + * + * This header file defines the generic integer types that will be used + * for the implementation of hash functions; it also contains helper + * functions which encode and decode multi-byte integer values, using + * either little-endian or big-endian conventions. + * + * This file contains a compile-time test on the size of a byte + * (the unsigned char C type). If bytes are not octets, + * i.e. if they do not have a size of exactly 8 bits, then compilation + * is aborted. Architectures where bytes are not octets are relatively + * rare, even in the embedded devices market. We forbid non-octet bytes + * because there is no clear convention on how octet streams are encoded + * on such systems. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @file sph_types.h + * @author Thomas Pornin + */ + +#ifndef GROESTL_INTERNAL_H__ +#define GROESTL_INTERNAL_H__ + +#include + +/* + * All our I/O functions are defined over octet streams. We do not know + * how to handle input data if bytes are not octets. + */ +#if CHAR_BIT != 8 +#error This code requires 8-bit bytes +#endif + +#if defined __STDC__ && __STDC_VERSION__ >= 199901L + +#include + +typedef uint32_t sph_u32; +typedef int32_t sph_s32; +typedef uint64_t sph_u64; +typedef int64_t sph_s64; + +#define SPH_C32(x) ((sph_u32)(x)) +#define SPH_C64(x) ((sph_u64)(x)) + +#else +#error We need at least C99 compiler +#endif + +#define SPH_T32(x) ((x)&SPH_C32(0xFFFFFFFF)) +#define SPH_ROTL32(x, n) SPH_T32(((x) << (n)) | ((x) >> (32 - (n)))) +#define SPH_ROTR32(x, n) SPH_ROTL32(x, (32 - (n))) + +#define SPH_T64(x) ((x)&SPH_C64(0xFFFFFFFFFFFFFFFF)) +#define SPH_ROTL64(x, n) SPH_T64(((x) << (n)) | ((x) >> (64 - (n)))) +#define SPH_ROTR64(x, n) SPH_ROTL64(x, (64 - (n))) + +/* + * 32-bit x86, aka "i386 compatible". + */ +#if defined __i386__ || defined _M_IX86 + +#define SPH_DETECT_LITTLE_ENDIAN 1 +#define SPH_DETECT_BIG_ENDIAN 0 + +/* + * 64-bit x86, hereafter known as "amd64". + */ +#elif defined __x86_64 || defined _M_X64 + +#define SPH_DETECT_LITTLE_ENDIAN 1 +#define SPH_DETECT_BIG_ENDIAN 0 + +/* + * ARM, little-endian. + */ +#elif defined __arm__ && __ARMEL__ + +#define SPH_DETECT_LITTLE_ENDIAN 1 +#define SPH_DETECT_BIG_ENDIAN 0 + +/* + * ARM64, little-endian. + */ +#elif defined __aarch64__ + +#define SPH_DETECT_LITTLE_ENDIAN 1 +#define SPH_DETECT_BIG_ENDIAN 0 + +#endif + +#if defined SPH_DETECT_LITTLE_ENDIAN && !defined SPH_LITTLE_ENDIAN +#define SPH_LITTLE_ENDIAN SPH_DETECT_LITTLE_ENDIAN +#endif +#if defined SPH_DETECT_BIG_ENDIAN && !defined SPH_BIG_ENDIAN +#define SPH_BIG_ENDIAN SPH_DETECT_BIG_ENDIAN +#endif + +static inline sph_u32 sph_bswap32(sph_u32 x) { + x = SPH_T32((x << 16) | (x >> 16)); + x = ((x & SPH_C32(0xFF00FF00)) >> 8) | ((x & SPH_C32(0x00FF00FF)) << 8); + return x; +} + +/** + * Byte-swap a 64-bit value. + * + * @param x the input value + * @return the byte-swapped value + */ +static inline sph_u64 sph_bswap64(sph_u64 x) { + x = SPH_T64((x << 32) | (x >> 32)); + x = ((x & SPH_C64(0xFFFF0000FFFF0000)) >> 16) | ((x & SPH_C64(0x0000FFFF0000FFFF)) << 16); + x = ((x & SPH_C64(0xFF00FF00FF00FF00)) >> 8) | ((x & SPH_C64(0x00FF00FF00FF00FF)) << 8); + return x; +} + +static inline void sph_enc16be(void* dst, unsigned val) { + ((unsigned char*)dst)[0] = (val >> 8); + ((unsigned char*)dst)[1] = val; +} + +static inline unsigned sph_dec16be(const void* src) { + return ((unsigned)(((const unsigned char*)src)[0]) << 8) | + (unsigned)(((const unsigned char*)src)[1]); +} + +static inline void sph_enc16le(void* dst, unsigned val) { + ((unsigned char*)dst)[0] = val; + ((unsigned char*)dst)[1] = val >> 8; +} + +static inline unsigned sph_dec16le(const void* src) { + return (unsigned)(((const unsigned char*)src)[0]) | + ((unsigned)(((const unsigned char*)src)[1]) << 8); +} + +/** + * Encode a 32-bit value into the provided buffer (big endian convention). + * + * @param dst the destination buffer + * @param val the 32-bit value to encode + */ +static inline void sph_enc32be(void* dst, sph_u32 val) { + ((unsigned char*)dst)[0] = (val >> 24); + ((unsigned char*)dst)[1] = (val >> 16); + ((unsigned char*)dst)[2] = (val >> 8); + ((unsigned char*)dst)[3] = val; +} + +/** + * Encode a 32-bit value into the provided buffer (big endian convention). + * The destination buffer must be properly aligned. + * + * @param dst the destination buffer (32-bit aligned) + * @param val the value to encode + */ +static inline void sph_enc32be_aligned(void* dst, sph_u32 val) { +#if SPH_LITTLE_ENDIAN + *(sph_u32*)dst = sph_bswap32(val); +#elif SPH_BIG_ENDIAN + *(sph_u32*)dst = val; +#else + ((unsigned char*)dst)[0] = (val >> 24); + ((unsigned char*)dst)[1] = (val >> 16); + ((unsigned char*)dst)[2] = (val >> 8); + ((unsigned char*)dst)[3] = val; +#endif +} + +/** + * Decode a 32-bit value from the provided buffer (big endian convention). + * + * @param src the source buffer + * @return the decoded value + */ +static inline sph_u32 sph_dec32be(const void* src) { + return ((sph_u32)(((const unsigned char*)src)[0]) << 24) | + ((sph_u32)(((const unsigned char*)src)[1]) << 16) | + ((sph_u32)(((const unsigned char*)src)[2]) << 8) | + (sph_u32)(((const unsigned char*)src)[3]); +} + +/** + * Decode a 32-bit value from the provided buffer (big endian convention). + * The source buffer must be properly aligned. + * + * @param src the source buffer (32-bit aligned) + * @return the decoded value + */ +static inline sph_u32 sph_dec32be_aligned(const void* src) { +#if SPH_LITTLE_ENDIAN + return sph_bswap32(*(const sph_u32*)src); +#elif SPH_BIG_ENDIAN + return *(const sph_u32*)src; +#else + return ((sph_u32)(((const unsigned char*)src)[0]) << 24) | + ((sph_u32)(((const unsigned char*)src)[1]) << 16) | + ((sph_u32)(((const unsigned char*)src)[2]) << 8) | + (sph_u32)(((const unsigned char*)src)[3]); +#endif +} + +/** + * Encode a 32-bit value into the provided buffer (little endian convention). + * + * @param dst the destination buffer + * @param val the 32-bit value to encode + */ +static inline void sph_enc32le(void* dst, sph_u32 val) { + ((unsigned char*)dst)[0] = val; + ((unsigned char*)dst)[1] = (val >> 8); + ((unsigned char*)dst)[2] = (val >> 16); + ((unsigned char*)dst)[3] = (val >> 24); +} + +/** + * Encode a 32-bit value into the provided buffer (little endian convention). + * The destination buffer must be properly aligned. + * + * @param dst the destination buffer (32-bit aligned) + * @param val the value to encode + */ +static inline void sph_enc32le_aligned(void* dst, sph_u32 val) { +#if SPH_LITTLE_ENDIAN + *(sph_u32*)dst = val; +#elif SPH_BIG_ENDIAN + *(sph_u32*)dst = sph_bswap32(val); +#else + ((unsigned char*)dst)[0] = val; + ((unsigned char*)dst)[1] = (val >> 8); + ((unsigned char*)dst)[2] = (val >> 16); + ((unsigned char*)dst)[3] = (val >> 24); +#endif +} + +/** + * Decode a 32-bit value from the provided buffer (little endian convention). + * + * @param src the source buffer + * @return the decoded value + */ +static inline sph_u32 sph_dec32le(const void* src) { + return (sph_u32)(((const unsigned char*)src)[0]) | + ((sph_u32)(((const unsigned char*)src)[1]) << 8) | + ((sph_u32)(((const unsigned char*)src)[2]) << 16) | + ((sph_u32)(((const unsigned char*)src)[3]) << 24); +} + +/** + * Decode a 32-bit value from the provided buffer (little endian convention). + * The source buffer must be properly aligned. + * + * @param src the source buffer (32-bit aligned) + * @return the decoded value + */ +static inline sph_u32 sph_dec32le_aligned(const void* src) { +#if SPH_LITTLE_ENDIAN + return *(const sph_u32*)src; +#elif SPH_BIG_ENDIAN + return sph_bswap32(*(const sph_u32*)src); +#else + return (sph_u32)(((const unsigned char*)src)[0]) | + ((sph_u32)(((const unsigned char*)src)[1]) << 8) | + ((sph_u32)(((const unsigned char*)src)[2]) << 16) | + ((sph_u32)(((const unsigned char*)src)[3]) << 24); +#endif +} + +/** + * Encode a 64-bit value into the provided buffer (big endian convention). + * + * @param dst the destination buffer + * @param val the 64-bit value to encode + */ +static inline void sph_enc64be(void* dst, sph_u64 val) { + ((unsigned char*)dst)[0] = (val >> 56); + ((unsigned char*)dst)[1] = (val >> 48); + ((unsigned char*)dst)[2] = (val >> 40); + ((unsigned char*)dst)[3] = (val >> 32); + ((unsigned char*)dst)[4] = (val >> 24); + ((unsigned char*)dst)[5] = (val >> 16); + ((unsigned char*)dst)[6] = (val >> 8); + ((unsigned char*)dst)[7] = val; +} + +/** + * Encode a 64-bit value into the provided buffer (big endian convention). + * The destination buffer must be properly aligned. + * + * @param dst the destination buffer (64-bit aligned) + * @param val the value to encode + */ +static inline void sph_enc64be_aligned(void* dst, sph_u64 val) { +#if SPH_LITTLE_ENDIAN + *(sph_u64*)dst = sph_bswap64(val); +#elif SPH_BIG_ENDIAN + *(sph_u64*)dst = val; +#else + ((unsigned char*)dst)[0] = (val >> 56); + ((unsigned char*)dst)[1] = (val >> 48); + ((unsigned char*)dst)[2] = (val >> 40); + ((unsigned char*)dst)[3] = (val >> 32); + ((unsigned char*)dst)[4] = (val >> 24); + ((unsigned char*)dst)[5] = (val >> 16); + ((unsigned char*)dst)[6] = (val >> 8); + ((unsigned char*)dst)[7] = val; +#endif +} + +/** + * Decode a 64-bit value from the provided buffer (big endian convention). + * + * @param src the source buffer + * @return the decoded value + */ +static inline sph_u64 sph_dec64be(const void* src) { + return ((sph_u64)(((const unsigned char*)src)[0]) << 56) | + ((sph_u64)(((const unsigned char*)src)[1]) << 48) | + ((sph_u64)(((const unsigned char*)src)[2]) << 40) | + ((sph_u64)(((const unsigned char*)src)[3]) << 32) | + ((sph_u64)(((const unsigned char*)src)[4]) << 24) | + ((sph_u64)(((const unsigned char*)src)[5]) << 16) | + ((sph_u64)(((const unsigned char*)src)[6]) << 8) | + (sph_u64)(((const unsigned char*)src)[7]); +} + +/** + * Decode a 64-bit value from the provided buffer (big endian convention). + * The source buffer must be properly aligned. + * + * @param src the source buffer (64-bit aligned) + * @return the decoded value + */ +static inline sph_u64 sph_dec64be_aligned(const void* src) { +#if SPH_LITTLE_ENDIAN + return sph_bswap64(*(const sph_u64*)src); +#elif SPH_BIG_ENDIAN + return *(const sph_u64*)src; +#else + return ((sph_u64)(((const unsigned char*)src)[0]) << 56) | + ((sph_u64)(((const unsigned char*)src)[1]) << 48) | + ((sph_u64)(((const unsigned char*)src)[2]) << 40) | + ((sph_u64)(((const unsigned char*)src)[3]) << 32) | + ((sph_u64)(((const unsigned char*)src)[4]) << 24) | + ((sph_u64)(((const unsigned char*)src)[5]) << 16) | + ((sph_u64)(((const unsigned char*)src)[6]) << 8) | + (sph_u64)(((const unsigned char*)src)[7]); +#endif +} + +/** + * Encode a 64-bit value into the provided buffer (little endian convention). + * + * @param dst the destination buffer + * @param val the 64-bit value to encode + */ +static inline void sph_enc64le(void* dst, sph_u64 val) { + ((unsigned char*)dst)[0] = val; + ((unsigned char*)dst)[1] = (val >> 8); + ((unsigned char*)dst)[2] = (val >> 16); + ((unsigned char*)dst)[3] = (val >> 24); + ((unsigned char*)dst)[4] = (val >> 32); + ((unsigned char*)dst)[5] = (val >> 40); + ((unsigned char*)dst)[6] = (val >> 48); + ((unsigned char*)dst)[7] = (val >> 56); +} + +/** + * Encode a 64-bit value into the provided buffer (little endian convention). + * The destination buffer must be properly aligned. + * + * @param dst the destination buffer (64-bit aligned) + * @param val the value to encode + */ +static inline void sph_enc64le_aligned(void* dst, sph_u64 val) { +#if SPH_LITTLE_ENDIAN + *(sph_u64*)dst = val; +#elif SPH_BIG_ENDIAN + *(sph_u64*)dst = sph_bswap64(val); +#else + ((unsigned char*)dst)[0] = val; + ((unsigned char*)dst)[1] = (val >> 8); + ((unsigned char*)dst)[2] = (val >> 16); + ((unsigned char*)dst)[3] = (val >> 24); + ((unsigned char*)dst)[4] = (val >> 32); + ((unsigned char*)dst)[5] = (val >> 40); + ((unsigned char*)dst)[6] = (val >> 48); + ((unsigned char*)dst)[7] = (val >> 56); +#endif +} + +/** + * Decode a 64-bit value from the provided buffer (little endian convention). + * + * @param src the source buffer + * @return the decoded value + */ +static inline sph_u64 sph_dec64le(const void* src) { + return (sph_u64)(((const unsigned char*)src)[0]) | + ((sph_u64)(((const unsigned char*)src)[1]) << 8) | + ((sph_u64)(((const unsigned char*)src)[2]) << 16) | + ((sph_u64)(((const unsigned char*)src)[3]) << 24) | + ((sph_u64)(((const unsigned char*)src)[4]) << 32) | + ((sph_u64)(((const unsigned char*)src)[5]) << 40) | + ((sph_u64)(((const unsigned char*)src)[6]) << 48) | + ((sph_u64)(((const unsigned char*)src)[7]) << 56); +} + +/** + * Decode a 64-bit value from the provided buffer (little endian convention). + * The source buffer must be properly aligned. + * + * @param src the source buffer (64-bit aligned) + * @return the decoded value + */ +static inline sph_u64 sph_dec64le_aligned(const void* src) { +#if SPH_LITTLE_ENDIAN + return *(const sph_u64*)src; +#elif SPH_BIG_ENDIAN + return sph_bswap64(*(const sph_u64*)src); +#else + return (sph_u64)(((const unsigned char*)src)[0]) | + ((sph_u64)(((const unsigned char*)src)[1]) << 8) | + ((sph_u64)(((const unsigned char*)src)[2]) << 16) | + ((sph_u64)(((const unsigned char*)src)[3]) << 24) | + ((sph_u64)(((const unsigned char*)src)[4]) << 32) | + ((sph_u64)(((const unsigned char*)src)[5]) << 40) | + ((sph_u64)(((const unsigned char*)src)[6]) << 48) | + ((sph_u64)(((const unsigned char*)src)[7]) << 56); +#endif +} + +#endif diff --git a/applications/external/flipbip/lib/crypto/hasher.c b/applications/external/flipbip/lib/crypto/hasher.c new file mode 100644 index 000000000..799ea6335 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/hasher.c @@ -0,0 +1,164 @@ +/** + * Copyright (c) 2017 Saleem Rashid + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "hasher.h" +#include "ripemd160.h" + +const uint32_t sha256_initial_tapsighash_state[8] = { + 0xf504a425UL, + 0xd7f8783bUL, + 0x1363868aUL, + 0xe3e55658UL, + 0x6eee945dUL, + 0xbc7888ddUL, + 0x02a6e2c3UL, + 0x1873fe9fUL, +}; + +void hasher_InitParam(Hasher* hasher, HasherType type, const void* param, uint32_t param_size) { + hasher->type = type; + hasher->param = param; + hasher->param_size = param_size; + + switch(hasher->type) { + case HASHER_SHA2: + case HASHER_SHA2D: + case HASHER_SHA2_RIPEMD: + sha256_Init(&hasher->ctx.sha2); + break; + case HASHER_SHA2_TAPSIGHASH: + sha256_Init_ex(&hasher->ctx.sha2, sha256_initial_tapsighash_state, 512); + break; + case HASHER_SHA3: +#if USE_KECCAK + case HASHER_SHA3K: +#endif + sha3_256_Init(&hasher->ctx.sha3); + break; + case HASHER_BLAKE: + case HASHER_BLAKED: + case HASHER_BLAKE_RIPEMD: + blake256_Init(&hasher->ctx.blake); + break; + case HASHER_GROESTLD_TRUNC: + groestl512_Init(&hasher->ctx.groestl); + break; + case HASHER_BLAKE2B: + blake2b_Init(&hasher->ctx.blake2b, 32); + break; + case HASHER_BLAKE2B_PERSONAL: + blake2b_InitPersonal(&hasher->ctx.blake2b, 32, hasher->param, hasher->param_size); + break; + } +} + +void hasher_Init(Hasher* hasher, HasherType type) { + hasher_InitParam(hasher, type, NULL, 0); +} + +void hasher_Reset(Hasher* hasher) { + hasher_InitParam(hasher, hasher->type, hasher->param, hasher->param_size); +} + +void hasher_Update(Hasher* hasher, const uint8_t* data, size_t length) { + switch(hasher->type) { + case HASHER_SHA2: + case HASHER_SHA2D: + case HASHER_SHA2_RIPEMD: + case HASHER_SHA2_TAPSIGHASH: + sha256_Update(&hasher->ctx.sha2, data, length); + break; + case HASHER_SHA3: +#if USE_KECCAK + case HASHER_SHA3K: +#endif + sha3_Update(&hasher->ctx.sha3, data, length); + break; + case HASHER_BLAKE: + case HASHER_BLAKED: + case HASHER_BLAKE_RIPEMD: + blake256_Update(&hasher->ctx.blake, data, length); + break; + case HASHER_GROESTLD_TRUNC: + groestl512_Update(&hasher->ctx.groestl, data, length); + break; + case HASHER_BLAKE2B: + case HASHER_BLAKE2B_PERSONAL: + blake2b_Update(&hasher->ctx.blake2b, data, length); + break; + } +} + +void hasher_Final(Hasher* hasher, uint8_t hash[HASHER_DIGEST_LENGTH]) { + switch(hasher->type) { + case HASHER_SHA2: + case HASHER_SHA2_TAPSIGHASH: + sha256_Final(&hasher->ctx.sha2, hash); + break; + case HASHER_SHA2D: + sha256_Final(&hasher->ctx.sha2, hash); + hasher_Raw(HASHER_SHA2, hash, HASHER_DIGEST_LENGTH, hash); + break; + case HASHER_SHA2_RIPEMD: + sha256_Final(&hasher->ctx.sha2, hash); + ripemd160(hash, HASHER_DIGEST_LENGTH, hash); + break; + case HASHER_SHA3: + sha3_Final(&hasher->ctx.sha3, hash); + break; +#if USE_KECCAK + case HASHER_SHA3K: + keccak_Final(&hasher->ctx.sha3, hash); + break; +#endif + case HASHER_BLAKE: + blake256_Final(&hasher->ctx.blake, hash); + break; + case HASHER_BLAKED: + blake256_Final(&hasher->ctx.blake, hash); + hasher_Raw(HASHER_BLAKE, hash, HASHER_DIGEST_LENGTH, hash); + break; + case HASHER_BLAKE_RIPEMD: + blake256_Final(&hasher->ctx.blake, hash); + ripemd160(hash, HASHER_DIGEST_LENGTH, hash); + break; + case HASHER_GROESTLD_TRUNC: + groestl512_DoubleTrunc(&hasher->ctx.groestl, hash); + break; + case HASHER_BLAKE2B: + case HASHER_BLAKE2B_PERSONAL: + blake2b_Final(&hasher->ctx.blake2b, hash, 32); + break; + } +} + +void hasher_Raw( + HasherType type, + const uint8_t* data, + size_t length, + uint8_t hash[HASHER_DIGEST_LENGTH]) { + Hasher hasher = {0}; + + hasher_Init(&hasher, type); + hasher_Update(&hasher, data, length); + hasher_Final(&hasher, hash); +} diff --git a/applications/external/flipbip/lib/crypto/hasher.h b/applications/external/flipbip/lib/crypto/hasher.h new file mode 100644 index 000000000..5130df416 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/hasher.h @@ -0,0 +1,85 @@ +/** + * Copyright (c) 2017 Saleem Rashid + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __HASHER_H__ +#define __HASHER_H__ + +#include +#include + +#include "blake256.h" +#include "blake2b.h" +#include "groestl.h" +#include "sha2.h" +#include "sha3.h" + +#define HASHER_DIGEST_LENGTH 32 + +typedef enum { + HASHER_SHA2, + HASHER_SHA2D, + HASHER_SHA2_RIPEMD, + HASHER_SHA2_TAPSIGHASH, + + HASHER_SHA3, +#if USE_KECCAK + HASHER_SHA3K, +#endif + + HASHER_BLAKE, + HASHER_BLAKED, + HASHER_BLAKE_RIPEMD, + + HASHER_GROESTLD_TRUNC, /* Double Groestl512 hasher truncated to 256 bits */ + + HASHER_BLAKE2B, + HASHER_BLAKE2B_PERSONAL, +} HasherType; + +typedef struct { + HasherType type; + + union { + SHA256_CTX sha2; // for HASHER_SHA2{,D} + SHA3_CTX sha3; // for HASHER_SHA3{,K} + BLAKE256_CTX blake; // for HASHER_BLAKE{,D} + GROESTL512_CTX groestl; // for HASHER_GROESTLD_TRUNC + BLAKE2B_CTX blake2b; // for HASHER_BLAKE2B{,_PERSONAL} + } ctx; + + const void* param; + uint32_t param_size; +} Hasher; + +void hasher_InitParam(Hasher* hasher, HasherType type, const void* param, uint32_t param_size); +void hasher_Init(Hasher* hasher, HasherType type); +void hasher_Reset(Hasher* hasher); +void hasher_Update(Hasher* hasher, const uint8_t* data, size_t length); +void hasher_Final(Hasher* hasher, uint8_t hash[HASHER_DIGEST_LENGTH]); + +void hasher_Raw( + HasherType type, + const uint8_t* data, + size_t length, + uint8_t hash[HASHER_DIGEST_LENGTH]); + +#endif diff --git a/applications/external/flipbip/lib/crypto/hmac.c b/applications/external/flipbip/lib/crypto/hmac.c new file mode 100644 index 000000000..1ee02711a --- /dev/null +++ b/applications/external/flipbip/lib/crypto/hmac.c @@ -0,0 +1,186 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include "hmac.h" +#include "memzero.h" +#include "options.h" + +void hmac_sha256_Init(HMAC_SHA256_CTX* hctx, const uint8_t* key, const uint32_t keylen) { + static CONFIDENTIAL uint8_t i_key_pad[SHA256_BLOCK_LENGTH]; + memzero(i_key_pad, SHA256_BLOCK_LENGTH); + if(keylen > SHA256_BLOCK_LENGTH) { + sha256_Raw(key, keylen, i_key_pad); + } else { + memcpy(i_key_pad, key, keylen); + } + for(int i = 0; i < SHA256_BLOCK_LENGTH; i++) { + hctx->o_key_pad[i] = i_key_pad[i] ^ 0x5c; + i_key_pad[i] ^= 0x36; + } + sha256_Init(&(hctx->ctx)); + sha256_Update(&(hctx->ctx), i_key_pad, SHA256_BLOCK_LENGTH); + memzero(i_key_pad, sizeof(i_key_pad)); +} + +void hmac_sha256_Update(HMAC_SHA256_CTX* hctx, const uint8_t* msg, const uint32_t msglen) { + sha256_Update(&(hctx->ctx), msg, msglen); +} + +void hmac_sha256_Final(HMAC_SHA256_CTX* hctx, uint8_t* hmac) { + sha256_Final(&(hctx->ctx), hmac); + sha256_Init(&(hctx->ctx)); + sha256_Update(&(hctx->ctx), hctx->o_key_pad, SHA256_BLOCK_LENGTH); + sha256_Update(&(hctx->ctx), hmac, SHA256_DIGEST_LENGTH); + sha256_Final(&(hctx->ctx), hmac); + memzero(hctx, sizeof(HMAC_SHA256_CTX)); +} + +void hmac_sha256( + const uint8_t* key, + const uint32_t keylen, + const uint8_t* msg, + const uint32_t msglen, + uint8_t* hmac) { + static CONFIDENTIAL HMAC_SHA256_CTX hctx; + hmac_sha256_Init(&hctx, key, keylen); + hmac_sha256_Update(&hctx, msg, msglen); + hmac_sha256_Final(&hctx, hmac); +} + +void hmac_sha256_prepare( + const uint8_t* key, + const uint32_t keylen, + uint32_t* opad_digest, + uint32_t* ipad_digest) { + static CONFIDENTIAL uint32_t key_pad[SHA256_BLOCK_LENGTH / sizeof(uint32_t)]; + + memzero(key_pad, sizeof(key_pad)); + if(keylen > SHA256_BLOCK_LENGTH) { + static CONFIDENTIAL SHA256_CTX context; + sha256_Init(&context); + sha256_Update(&context, key, keylen); + sha256_Final(&context, (uint8_t*)key_pad); + } else { + memcpy(key_pad, key, keylen); + } + + /* compute o_key_pad and its digest */ + for(int i = 0; i < SHA256_BLOCK_LENGTH / (int)sizeof(uint32_t); i++) { + uint32_t data = 0; +#if BYTE_ORDER == LITTLE_ENDIAN + REVERSE32(key_pad[i], data); +#else + data = key_pad[i]; +#endif + key_pad[i] = data ^ 0x5c5c5c5c; + } + sha256_Transform(sha256_initial_hash_value, key_pad, opad_digest); + + /* convert o_key_pad to i_key_pad and compute its digest */ + for(int i = 0; i < SHA256_BLOCK_LENGTH / (int)sizeof(uint32_t); i++) { + key_pad[i] = key_pad[i] ^ 0x5c5c5c5c ^ 0x36363636; + } + sha256_Transform(sha256_initial_hash_value, key_pad, ipad_digest); + memzero(key_pad, sizeof(key_pad)); +} + +void hmac_sha512_Init(HMAC_SHA512_CTX* hctx, const uint8_t* key, const uint32_t keylen) { + static CONFIDENTIAL uint8_t i_key_pad[SHA512_BLOCK_LENGTH]; + memzero(i_key_pad, SHA512_BLOCK_LENGTH); + if(keylen > SHA512_BLOCK_LENGTH) { + sha512_Raw(key, keylen, i_key_pad); + } else { + memcpy(i_key_pad, key, keylen); + } + for(int i = 0; i < SHA512_BLOCK_LENGTH; i++) { + hctx->o_key_pad[i] = i_key_pad[i] ^ 0x5c; + i_key_pad[i] ^= 0x36; + } + sha512_Init(&(hctx->ctx)); + sha512_Update(&(hctx->ctx), i_key_pad, SHA512_BLOCK_LENGTH); + memzero(i_key_pad, sizeof(i_key_pad)); +} + +void hmac_sha512_Update(HMAC_SHA512_CTX* hctx, const uint8_t* msg, const uint32_t msglen) { + sha512_Update(&(hctx->ctx), msg, msglen); +} + +void hmac_sha512_Final(HMAC_SHA512_CTX* hctx, uint8_t* hmac) { + sha512_Final(&(hctx->ctx), hmac); + sha512_Init(&(hctx->ctx)); + sha512_Update(&(hctx->ctx), hctx->o_key_pad, SHA512_BLOCK_LENGTH); + sha512_Update(&(hctx->ctx), hmac, SHA512_DIGEST_LENGTH); + sha512_Final(&(hctx->ctx), hmac); + memzero(hctx, sizeof(HMAC_SHA512_CTX)); +} + +void hmac_sha512( + const uint8_t* key, + const uint32_t keylen, + const uint8_t* msg, + const uint32_t msglen, + uint8_t* hmac) { + HMAC_SHA512_CTX hctx = {0}; + hmac_sha512_Init(&hctx, key, keylen); + hmac_sha512_Update(&hctx, msg, msglen); + hmac_sha512_Final(&hctx, hmac); +} + +void hmac_sha512_prepare( + const uint8_t* key, + const uint32_t keylen, + uint64_t* opad_digest, + uint64_t* ipad_digest) { + static CONFIDENTIAL uint64_t key_pad[SHA512_BLOCK_LENGTH / sizeof(uint64_t)]; + + memzero(key_pad, sizeof(key_pad)); + if(keylen > SHA512_BLOCK_LENGTH) { + static CONFIDENTIAL SHA512_CTX context; + sha512_Init(&context); + sha512_Update(&context, key, keylen); + sha512_Final(&context, (uint8_t*)key_pad); + } else { + memcpy(key_pad, key, keylen); + } + + /* compute o_key_pad and its digest */ + for(int i = 0; i < SHA512_BLOCK_LENGTH / (int)sizeof(uint64_t); i++) { + uint64_t data = 0; +#if BYTE_ORDER == LITTLE_ENDIAN + REVERSE64(key_pad[i], data); +#else + data = key_pad[i]; +#endif + key_pad[i] = data ^ 0x5c5c5c5c5c5c5c5c; + } + sha512_Transform(sha512_initial_hash_value, key_pad, opad_digest); + + /* convert o_key_pad to i_key_pad and compute its digest */ + for(int i = 0; i < SHA512_BLOCK_LENGTH / (int)sizeof(uint64_t); i++) { + key_pad[i] = key_pad[i] ^ 0x5c5c5c5c5c5c5c5c ^ 0x3636363636363636; + } + sha512_Transform(sha512_initial_hash_value, key_pad, ipad_digest); + memzero(key_pad, sizeof(key_pad)); +} diff --git a/applications/external/flipbip/lib/crypto/hmac.h b/applications/external/flipbip/lib/crypto/hmac.h new file mode 100644 index 000000000..21a4f8da6 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/hmac.h @@ -0,0 +1,70 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT HMAC_SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __HMAC_H__ +#define __HMAC_H__ + +#include +#include "sha2.h" + +typedef struct _HMAC_SHA256_CTX { + uint8_t o_key_pad[SHA256_BLOCK_LENGTH]; + SHA256_CTX ctx; +} HMAC_SHA256_CTX; + +typedef struct _HMAC_SHA512_CTX { + uint8_t o_key_pad[SHA512_BLOCK_LENGTH]; + SHA512_CTX ctx; +} HMAC_SHA512_CTX; + +void hmac_sha256_Init(HMAC_SHA256_CTX* hctx, const uint8_t* key, const uint32_t keylen); +void hmac_sha256_Update(HMAC_SHA256_CTX* hctx, const uint8_t* msg, const uint32_t msglen); +void hmac_sha256_Final(HMAC_SHA256_CTX* hctx, uint8_t* hmac); +void hmac_sha256( + const uint8_t* key, + const uint32_t keylen, + const uint8_t* msg, + const uint32_t msglen, + uint8_t* hmac); +void hmac_sha256_prepare( + const uint8_t* key, + const uint32_t keylen, + uint32_t* opad_digest, + uint32_t* ipad_digest); + +void hmac_sha512_Init(HMAC_SHA512_CTX* hctx, const uint8_t* key, const uint32_t keylen); +void hmac_sha512_Update(HMAC_SHA512_CTX* hctx, const uint8_t* msg, const uint32_t msglen); +void hmac_sha512_Final(HMAC_SHA512_CTX* hctx, uint8_t* hmac); +void hmac_sha512( + const uint8_t* key, + const uint32_t keylen, + const uint8_t* msg, + const uint32_t msglen, + uint8_t* hmac); +void hmac_sha512_prepare( + const uint8_t* key, + const uint32_t keylen, + uint64_t* opad_digest, + uint64_t* ipad_digest); + +#endif diff --git a/applications/external/flipbip/lib/crypto/hmac_drbg.c b/applications/external/flipbip/lib/crypto/hmac_drbg.c new file mode 100644 index 000000000..3115c11f2 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/hmac_drbg.c @@ -0,0 +1,141 @@ +/** + * Copyright (c) 2019 Andrew R. Kozlik + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "hmac_drbg.h" +#include +#include "memzero.h" +#include "sha2.h" + +static void update_k( + HMAC_DRBG_CTX* ctx, + uint8_t domain, + const uint8_t* data1, + size_t len1, + const uint8_t* data2, + size_t len2) { + // Computes K = HMAC(K, V || domain || data1 || data 2). + + // First hash operation of HMAC. + uint32_t h[SHA256_BLOCK_LENGTH / sizeof(uint32_t)] = {0}; + if(len1 + len2 == 0) { + ctx->v[8] = 0x00800000; + ctx->v[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH + 1) * 8; + sha256_Transform(ctx->idig, ctx->v, h); + ctx->v[8] = 0x80000000; + ctx->v[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH) * 8; + } else { + SHA256_CTX sha_ctx = {0}; + memcpy(sha_ctx.state, ctx->idig, SHA256_DIGEST_LENGTH); + for(size_t i = 0; i < SHA256_DIGEST_LENGTH / sizeof(uint32_t); i++) { +#if BYTE_ORDER == LITTLE_ENDIAN + REVERSE32(ctx->v[i], sha_ctx.buffer[i]); +#else + sha_ctx.buffer[i] = ctx->v[i]; +#endif + } + ((uint8_t*)sha_ctx.buffer)[SHA256_DIGEST_LENGTH] = domain; + sha_ctx.bitcount = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH + 1) * 8; + sha256_Update(&sha_ctx, data1, len1); + sha256_Update(&sha_ctx, data2, len2); + sha256_Final(&sha_ctx, (uint8_t*)h); +#if BYTE_ORDER == LITTLE_ENDIAN + for(size_t i = 0; i < SHA256_DIGEST_LENGTH / sizeof(uint32_t); i++) REVERSE32(h[i], h[i]); +#endif + } + + // Second hash operation of HMAC. + h[8] = 0x80000000; + h[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH) * 8; + sha256_Transform(ctx->odig, h, h); + + // Precompute the inner digest and outer digest of K. + h[8] = 0; + h[15] = 0; + for(size_t i = 0; i < SHA256_BLOCK_LENGTH / sizeof(uint32_t); i++) { + h[i] ^= 0x36363636; + } + sha256_Transform(sha256_initial_hash_value, h, ctx->idig); + + for(size_t i = 0; i < SHA256_BLOCK_LENGTH / sizeof(uint32_t); i++) { + h[i] = h[i] ^ 0x36363636 ^ 0x5c5c5c5c; + } + sha256_Transform(sha256_initial_hash_value, h, ctx->odig); + memzero(h, sizeof(h)); +} + +static void update_v(HMAC_DRBG_CTX* ctx) { + sha256_Transform(ctx->idig, ctx->v, ctx->v); + sha256_Transform(ctx->odig, ctx->v, ctx->v); +} + +void hmac_drbg_init( + HMAC_DRBG_CTX* ctx, + const uint8_t* entropy, + size_t entropy_len, + const uint8_t* nonce, + size_t nonce_len) { + uint32_t h[SHA256_BLOCK_LENGTH / sizeof(uint32_t)] = {0}; + + // Precompute the inner digest and outer digest of K = 0x00 ... 0x00. + memset(h, 0x36, sizeof(h)); + sha256_Transform(sha256_initial_hash_value, h, ctx->idig); + memset(h, 0x5c, sizeof(h)); + sha256_Transform(sha256_initial_hash_value, h, ctx->odig); + + // Let V = 0x01 ... 0x01. + memset(ctx->v, 1, SHA256_DIGEST_LENGTH); + for(size_t i = 9; i < 15; i++) ctx->v[i] = 0; + ctx->v[8] = 0x80000000; + ctx->v[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH) * 8; + + hmac_drbg_reseed(ctx, entropy, entropy_len, nonce, nonce_len); + + memzero(h, sizeof(h)); +} + +void hmac_drbg_reseed( + HMAC_DRBG_CTX* ctx, + const uint8_t* entropy, + size_t len, + const uint8_t* addin, + size_t addin_len) { + update_k(ctx, 0, entropy, len, addin, addin_len); + update_v(ctx); + if(len == 0) return; + update_k(ctx, 1, entropy, len, addin, addin_len); + update_v(ctx); +} + +void hmac_drbg_generate(HMAC_DRBG_CTX* ctx, uint8_t* buf, size_t len) { + size_t i = 0; + while(i < len) { + update_v(ctx); + for(size_t j = 0; j < 8 && i < len; j++) { + uint32_t r = ctx->v[j]; + for(int k = 24; k >= 0 && i < len; k -= 8) { + buf[i++] = (r >> k) & 0xFF; + } + } + } + update_k(ctx, 0, NULL, 0, NULL, 0); + update_v(ctx); +} diff --git a/applications/external/flipbip/lib/crypto/hmac_drbg.h b/applications/external/flipbip/lib/crypto/hmac_drbg.h new file mode 100644 index 000000000..f6d3f3732 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/hmac_drbg.h @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2019 Andrew R. Kozlik + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __HMAC_DRBG_H__ +#define __HMAC_DRBG_H__ + +#include "sha2.h" +#include + +// HMAC based Deterministic Random Bit Generator with SHA-256 + +typedef struct _HMAC_DRBG_CTX { + uint32_t odig[SHA256_DIGEST_LENGTH / sizeof(uint32_t)]; + uint32_t idig[SHA256_DIGEST_LENGTH / sizeof(uint32_t)]; + uint32_t v[SHA256_BLOCK_LENGTH / sizeof(uint32_t)]; +} HMAC_DRBG_CTX; + +void hmac_drbg_init( + HMAC_DRBG_CTX* ctx, + const uint8_t* buf, + size_t len, + const uint8_t* nonce, + size_t nonce_len); +void hmac_drbg_reseed( + HMAC_DRBG_CTX* ctx, + const uint8_t* buf, + size_t len, + const uint8_t* addin, + size_t addin_len); +void hmac_drbg_generate(HMAC_DRBG_CTX* ctx, uint8_t* buf, size_t len); + +#endif diff --git a/applications/external/flipbip/lib/crypto/memzero.c b/applications/external/flipbip/lib/crypto/memzero.c new file mode 100644 index 000000000..64866ee56 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/memzero.c @@ -0,0 +1,74 @@ +#ifndef __STDC_WANT_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ 1 // C11's bounds-checking interface. +#endif +#include + +#ifdef _WIN32 +#include +#endif + +#ifdef __unix__ +#include +#include +#endif + +// C11's bounds-checking interface. +#if defined(__STDC_LIB_EXT1__) +#define HAVE_MEMSET_S 1 +#endif + +// GNU C Library version 2.25 or later. +#if defined(__GLIBC__) && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25)) +#define HAVE_EXPLICIT_BZERO 1 +#endif + +// Newlib +#if defined(__NEWLIB__) +#define HAVE_EXPLICIT_BZERO 1 +#endif + +// FreeBSD version 11.0 or later. +#if defined(__FreeBSD__) && __FreeBSD_version >= 1100037 +#define HAVE_EXPLICIT_BZERO 1 +#endif + +// OpenBSD version 5.5 or later. +#if defined(__OpenBSD__) && OpenBSD >= 201405 +#define HAVE_EXPLICIT_BZERO 1 +#endif + +// NetBSD version 7.2 or later. +#if defined(__NetBSD__) && __NetBSD_Version__ >= 702000000 +#define HAVE_EXPLICIT_MEMSET 1 +#endif + +// Adapted from +// https://github.com/jedisct1/libsodium/blob/1647f0d53ae0e370378a9195477e3df0a792408f/src/libsodium/sodium/utils.c#L102-L130 + +void memzero(void* const pnt, const size_t len) { +#ifdef _WIN32 + SecureZeroMemory(pnt, len); +#elif defined(HAVE_MEMSET_S) + memset_s(pnt, (rsize_t)len, 0, (rsize_t)len); +// #elif defined(HAVE_EXPLICIT_BZERO) +// explicit_bzero(pnt, len); +#elif defined(HAVE_EXPLICIT_MEMSET) + explicit_memset(pnt, 0, len); +#else + volatile unsigned char* volatile pnt_ = (volatile unsigned char* volatile)pnt; + size_t i = (size_t)0U; + + while(i < len) { + pnt_[i++] = 0U; + } +#endif + + // explicitly mark the memory as overwritten for the Clang MemorySanitizer + // this is only included at compile time if MemorySanitizer is enabled and + // should not come with any downsides during regular builds +#if defined(__has_feature) +#if __has_feature(memory_sanitizer) + memset(pnt, 0, len); +#endif +#endif +} diff --git a/applications/external/flipbip/lib/crypto/memzero.h b/applications/external/flipbip/lib/crypto/memzero.h new file mode 100644 index 000000000..0a959fbc2 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/memzero.h @@ -0,0 +1,8 @@ +#ifndef __MEMZERO_H__ +#define __MEMZERO_H__ + +#include + +void memzero(void* const pnt, const size_t len); + +#endif diff --git a/applications/external/flipbip/lib/crypto/monero/base58.c b/applications/external/flipbip/lib/crypto/monero/base58.c new file mode 100644 index 000000000..1ca9dfafd --- /dev/null +++ b/applications/external/flipbip/lib/crypto/monero/base58.c @@ -0,0 +1,297 @@ +// Copyright (c) 2014-2018, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote +// developers + +#if USE_MONERO + +#include "base58.h" +#include +#include +#include +#include +#include "../base58.h" +#include "../byte_order.h" +#include "int_util.h" +#include "../sha2.h" + +const size_t alphabet_size = 58; // sizeof(b58digits_ordered) - 1; +const size_t full_encoded_block_size = 11; +const size_t encoded_block_sizes[] = {0, 2, 3, 5, 6, 7, 9, 10, full_encoded_block_size}; +const size_t full_block_size = sizeof(encoded_block_sizes) / sizeof(encoded_block_sizes[0]) - 1; +const size_t addr_checksum_size = 4; +const size_t max_bin_data_size = 72; +const int decoded_block_sizes[] = {0, -1, 1, 2, -1, 3, 4, 5, -1, 6, 7, 8}; +#define reverse_alphabet(letter) ((int8_t)b58digits_map[(int)letter]) + +uint64_t uint_8be_to_64(const uint8_t* data, size_t size) { + assert(1 <= size && size <= sizeof(uint64_t)); + + uint64_t res = 0; + switch(9 - size) { + case 1: + res |= *data++; /* FALLTHRU */ + case 2: + res <<= 8; + res |= *data++; /* FALLTHRU */ + case 3: + res <<= 8; + res |= *data++; /* FALLTHRU */ + case 4: + res <<= 8; + res |= *data++; /* FALLTHRU */ + case 5: + res <<= 8; + res |= *data++; /* FALLTHRU */ + case 6: + res <<= 8; + res |= *data++; /* FALLTHRU */ + case 7: + res <<= 8; + res |= *data++; /* FALLTHRU */ + case 8: + res <<= 8; + res |= *data; + break; + default: + assert(false); + } + + return res; +} + +void uint_64_to_8be(uint64_t num, size_t size, uint8_t* data) { + assert(1 <= size && size <= sizeof(uint64_t)); + +#if BYTE_ORDER == LITTLE_ENDIAN + uint64_t num_be = SWAP64(num); +#else + uint64_t num_be = num; +#endif + memcpy(data, (uint8_t*)(&num_be) + sizeof(uint64_t) - size, size); +} + +void encode_block(const char* block, size_t size, char* res) { + assert(1 <= size && size <= full_block_size); + + uint64_t num = uint_8be_to_64((uint8_t*)(block), size); + int i = ((int)(encoded_block_sizes[size])) - 1; + while(0 <= i) { + uint64_t remainder = num % alphabet_size; + num /= alphabet_size; + res[i] = b58digits_ordered[remainder]; + --i; + } +} + +bool decode_block(const char* block, size_t size, char* res) { + assert(1 <= size && size <= full_encoded_block_size); + + int res_size = decoded_block_sizes[size]; + if(res_size <= 0) { + return false; // Invalid block size + } + + uint64_t res_num = 0; + uint64_t order = 1; + for(size_t i = size - 1; i < size; --i) { + if(block[i] & 0x80) { + return false; // Invalid symbol + } + int digit = reverse_alphabet(block[i]); + if(digit < 0) { + return false; // Invalid symbol + } + + uint64_t product_hi = 0; + uint64_t tmp = res_num + mul128(order, (uint64_t)digit, &product_hi); + if(tmp < res_num || 0 != product_hi) { + return false; // Overflow + } + + res_num = tmp; + // The original code comment for the order multiplication says + // "Never overflows, 58^10 < 2^64" + // This is incorrect since it overflows on the 11th iteration + // However, there is no negative impact since the result is unused + order *= alphabet_size; + } + + if((size_t)res_size < full_block_size && (UINT64_C(1) << (8 * res_size)) <= res_num) + return false; // Overflow + + uint_64_to_8be(res_num, res_size, (uint8_t*)(res)); + + return true; +} + +bool xmr_base58_encode(char* b58, size_t* b58sz, const void* data, size_t binsz) { + if(binsz == 0) { + if(b58sz) { + *b58sz = 0; + } + return true; + } + + const char* data_bin = data; + size_t full_block_count = binsz / full_block_size; + size_t last_block_size = binsz % full_block_size; + size_t res_size = + full_block_count * full_encoded_block_size + encoded_block_sizes[last_block_size]; + + if(b58sz) { + if(res_size > *b58sz) { + return false; + } + *b58sz = res_size; + } + + for(size_t i = 0; i < full_block_count; ++i) { + encode_block( + data_bin + i * full_block_size, full_block_size, b58 + i * full_encoded_block_size); + } + + if(0 < last_block_size) { + encode_block( + data_bin + full_block_count * full_block_size, + last_block_size, + b58 + full_block_count * full_encoded_block_size); + } + + return true; +} + +bool xmr_base58_decode(const char* b58, size_t b58sz, void* data, size_t* binsz) { + if(b58sz == 0) { + *binsz = 0; + return true; + } + + size_t full_block_count = b58sz / full_encoded_block_size; + size_t last_block_size = b58sz % full_encoded_block_size; + int last_block_decoded_size = decoded_block_sizes[last_block_size]; + if(last_block_decoded_size < 0) { + *binsz = 0; + return false; // Invalid enc length + } + + size_t data_size = full_block_count * full_block_size + last_block_decoded_size; + if(*binsz < data_size) { + *binsz = 0; + return false; + } + + char* data_bin = data; + for(size_t i = 0; i < full_block_count; ++i) { + if(!decode_block( + b58 + i * full_encoded_block_size, + full_encoded_block_size, + data_bin + i * full_block_size)) { + *binsz = 0; + return false; + } + } + + if(0 < last_block_size) { + if(!decode_block( + b58 + full_block_count * full_encoded_block_size, + last_block_size, + data_bin + full_block_count * full_block_size)) { + *binsz = 0; + return false; + } + } + + *binsz = data_size; + return true; +} + +int xmr_base58_addr_encode_check( + uint64_t tag, + const uint8_t* data, + size_t binsz, + char* b58, + size_t b58sz) { + if(binsz > max_bin_data_size || tag > 127) { // tag varint + return false; + } + + size_t b58size = b58sz; + uint8_t buf[(binsz + 1) + HASHER_DIGEST_LENGTH]; + memset(buf, 0, sizeof(buf)); + uint8_t* hash = buf + binsz + 1; + buf[0] = (uint8_t)tag; + memcpy(buf + 1, data, binsz); + hasher_Raw(HASHER_SHA3K, buf, binsz + 1, hash); + + bool r = xmr_base58_encode(b58, &b58size, buf, binsz + 1 + addr_checksum_size); + return (int)(!r ? 0 : b58size); +} + +int xmr_base58_addr_decode_check( + const char* addr, + size_t sz, + uint64_t* tag, + void* data, + size_t datalen) { + size_t buflen = 1 + max_bin_data_size + addr_checksum_size; + uint8_t buf[buflen]; + memset(buf, 0, sizeof(buf)); + uint8_t hash[HASHER_DIGEST_LENGTH] = {0}; + + if(!xmr_base58_decode(addr, sz, buf, &buflen)) { + return 0; + } + + if(buflen <= addr_checksum_size + 1) { + return 0; + } + + size_t res_size = buflen - addr_checksum_size - 1; + if(datalen < res_size) { + return 0; + } + + hasher_Raw(HASHER_SHA3K, buf, buflen - addr_checksum_size, hash); + if(memcmp(hash, buf + buflen - addr_checksum_size, addr_checksum_size) != 0) { + return 0; + } + + *tag = buf[0]; + if(*tag > 127) { + return false; // varint + } + + memcpy(data, buf + 1, res_size); + return (int)res_size; +} + +#endif // USE_MONERO \ No newline at end of file diff --git a/applications/external/flipbip/lib/crypto/monero/base58.h b/applications/external/flipbip/lib/crypto/monero/base58.h new file mode 100644 index 000000000..adcafadd1 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/monero/base58.h @@ -0,0 +1,60 @@ +// Copyright (c) 2014-2018, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote +// developers + +#if USE_MONERO + +#ifndef __XMR_BASE58_H__ +#define __XMR_BASE58_H__ + +#include +#include "../hasher.h" +#include "../options.h" + +int xmr_base58_addr_encode_check( + uint64_t tag, + const uint8_t* data, + size_t binsz, + char* b58, + size_t b58sz); +int xmr_base58_addr_decode_check( + const char* addr, + size_t sz, + uint64_t* tag, + void* data, + size_t datalen); +bool xmr_base58_encode(char* b58, size_t* b58sz, const void* data, size_t binsz); +bool xmr_base58_decode(const char* b58, size_t b58sz, void* data, size_t* binsz); + +#endif + +#endif // USE_MONERO \ No newline at end of file diff --git a/applications/external/flipbip/lib/crypto/monero/int_util.h b/applications/external/flipbip/lib/crypto/monero/int_util.h new file mode 100644 index 000000000..fb627b62e --- /dev/null +++ b/applications/external/flipbip/lib/crypto/monero/int_util.h @@ -0,0 +1,81 @@ +// Copyright (c) 2014-2018, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote +// developers + +#if USE_MONERO + +#pragma once + +#include +#include + +static inline uint64_t hi_dword(uint64_t val) { + return val >> 32; +} + +static inline uint64_t lo_dword(uint64_t val) { + return val & 0xFFFFFFFF; +} + +static inline uint64_t mul128(uint64_t multiplier, uint64_t multiplicand, uint64_t* product_hi) { + // multiplier = ab = a * 2^32 + b + // multiplicand = cd = c * 2^32 + d + // ab * cd = a * c * 2^64 + (a * d + b * c) * 2^32 + b * d + uint64_t a = hi_dword(multiplier); + uint64_t b = lo_dword(multiplier); + uint64_t c = hi_dword(multiplicand); + uint64_t d = lo_dword(multiplicand); + + uint64_t ac = a * c; + uint64_t ad = a * d; + uint64_t bc = b * c; + uint64_t bd = b * d; + + uint64_t adbc = ad + bc; + uint64_t adbc_carry = adbc < ad ? 1 : 0; + + // multiplier * multiplicand = product_hi * 2^64 + product_lo + uint64_t product_lo = bd + (adbc << 32); + uint64_t product_lo_carry = product_lo < bd ? 1 : 0; + *product_hi = ac + (adbc >> 32) + (adbc_carry << 32) + product_lo_carry; + assert(ac <= *product_hi); + + return product_lo; +} + +#define SWAP64(x) \ + ((((uint64_t)(x)&0x00000000000000ff) << 56) | (((uint64_t)(x)&0x000000000000ff00) << 40) | \ + (((uint64_t)(x)&0x0000000000ff0000) << 24) | (((uint64_t)(x)&0x00000000ff000000) << 8) | \ + (((uint64_t)(x)&0x000000ff00000000) >> 8) | (((uint64_t)(x)&0x0000ff0000000000) >> 24) | \ + (((uint64_t)(x)&0x00ff000000000000) >> 40) | (((uint64_t)(x)&0xff00000000000000) >> 56)) + +#endif // USE_MONERO \ No newline at end of file diff --git a/applications/external/flipbip/lib/crypto/monero/monero.h b/applications/external/flipbip/lib/crypto/monero/monero.h new file mode 100644 index 000000000..96ff9dd5c --- /dev/null +++ b/applications/external/flipbip/lib/crypto/monero/monero.h @@ -0,0 +1,24 @@ +// +// Created by Dusan Klinec on 10/05/2018. +// + +#if USE_MONERO + +#ifndef TREZOR_CRYPTO_MONERO_H +#define TREZOR_CRYPTO_MONERO_H + +#if !USE_MONERO +#error "Compile with -DUSE_MONERO=1" +#endif + +#if !USE_KECCAK +#error "Compile with -DUSE_KECCAK=1" +#endif + +#include "base58.h" +#include "serialize.h" +#include "xmr.h" + +#endif // TREZOR_CRYPTO_MONERO_H + +#endif // USE_MONERO diff --git a/applications/external/flipbip/lib/crypto/monero/serialize.c b/applications/external/flipbip/lib/crypto/monero/serialize.c new file mode 100644 index 000000000..0023c9699 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/monero/serialize.c @@ -0,0 +1,57 @@ +// +// Created by Dusan Klinec on 02/05/2018. +// + +#if USE_MONERO + +#include "serialize.h" + +int xmr_size_varint(uint64_t num) { + int ctr = 1; + while(num >= 0x80) { + ++ctr; + num >>= 7; + } + return ctr; +} + +int xmr_write_varint(uint8_t* buff, size_t buff_size, uint64_t num) { + unsigned ctr = 0; + while(num >= 0x80 && ctr < buff_size) { + *buff = (uint8_t)(((num)&0x7f) | 0x80); + ++buff; + ++ctr; + num >>= 7; + } + + /* writes the last one to dest */ + if(ctr < buff_size) { + *buff = (uint8_t)num; + ++ctr; + } + return ctr <= buff_size ? (int)ctr : -1; +} + +int xmr_read_varint(uint8_t* buff, size_t buff_size, uint64_t* val) { + unsigned read = 0; + int finished_ok = 0; + *val = 0; + + for(int shift = 0; read < buff_size; shift += 7, ++read) { + uint8_t byte = buff[read]; + if((byte == 0 && shift != 0) || (shift >= 63 && byte > 1)) { + return -1; + } + + *val |= (uint64_t)(byte & 0x7f) << shift; + + /* If there is no next */ + if((byte & 0x80) == 0) { + finished_ok = 1; + break; + } + } + return finished_ok ? (int)read + 1 : -2; +} + +#endif // USE_MONERO diff --git a/applications/external/flipbip/lib/crypto/monero/serialize.h b/applications/external/flipbip/lib/crypto/monero/serialize.h new file mode 100644 index 000000000..9f8903694 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/monero/serialize.h @@ -0,0 +1,19 @@ +// +// Created by Dusan Klinec on 02/05/2018. +// + +#if USE_MONERO + +#ifndef TREZOR_XMR_SERIALIZE_H +#define TREZOR_XMR_SERIALIZE_H + +#include +#include + +int xmr_size_varint(uint64_t num); +int xmr_write_varint(uint8_t* buff, size_t buff_size, uint64_t num); +int xmr_read_varint(uint8_t* buff, size_t buff_size, uint64_t* val); + +#endif // TREZOR_XMR_SERIALIZE_H + +#endif // USE_MONERO diff --git a/applications/external/flipbip/lib/crypto/monero/xmr.c b/applications/external/flipbip/lib/crypto/monero/xmr.c new file mode 100644 index 000000000..917200624 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/monero/xmr.c @@ -0,0 +1,202 @@ +// +// Created by Dusan Klinec on 10/05/2018. +// + +#if USE_MONERO + +#include "xmr.h" +#include "../byte_order.h" +#include "int_util.h" +#include "../rand.h" +#include "serialize.h" + +const ge25519 ALIGN(16) xmr_h = { + {0x1861ec7, + 0x1ceac77, + 0x2f11626, + 0x1f261d3, + 0x346107c, + 0x06d8c4a, + 0x254201d, + 0x1675c09, + 0x1301c3f, + 0x0211d73}, + {0x326feb4, + 0x12e30cc, + 0x0cf54b4, + 0x1117305, + 0x318f5d5, + 0x06cf754, + 0x2e578a1, + 0x1daf058, + 0x34430a1, + 0x04410e9}, + {0x0fde4d2, + 0x0774049, + 0x22ca951, + 0x05aec2b, + 0x07a36a5, + 0x1394f13, + 0x3c5385c, + 0x1adb924, + 0x2b6c581, + 0x0a55fa4}, + {0x24517f7, + 0x05ee936, + 0x3acf5d9, + 0x14b08aa, + 0x3363738, + 0x1051745, + 0x360601e, + 0x0f3f2c9, + 0x1ead2cd, + 0x1d3e3df}}; + +void ge25519_set_xmr_h(ge25519* r) { + ge25519_copy(r, &xmr_h); +} + +void xmr_random_scalar(bignum256modm m) { + unsigned char buff[32] = {0}; + random_buffer(buff, sizeof(buff)); + expand256_modm(m, buff, sizeof(buff)); +} + +void xmr_fast_hash(uint8_t* hash, const void* data, size_t length) { + hasher_Raw(HASHER_SHA3K, data, length, hash); +} + +void xmr_hasher_init(Hasher* hasher) { + hasher_Init(hasher, HASHER_SHA3K); +} + +void xmr_hasher_update(Hasher* hasher, const void* data, size_t length) { + hasher_Update(hasher, data, length); +} + +void xmr_hasher_final(Hasher* hasher, uint8_t* hash) { + hasher_Final(hasher, hash); +} + +void xmr_hasher_copy(Hasher* dst, const Hasher* src) { + memcpy(dst, src, sizeof(Hasher)); +} + +void xmr_hash_to_scalar(bignum256modm r, const void* data, size_t length) { + uint8_t hash[HASHER_DIGEST_LENGTH] = {0}; + hasher_Raw(HASHER_SHA3K, data, length, hash); + expand256_modm(r, hash, HASHER_DIGEST_LENGTH); +} + +void xmr_hash_to_ec(ge25519* P, const void* data, size_t length) { + ge25519 point2 = {0}; + uint8_t hash[HASHER_DIGEST_LENGTH] = {0}; + hasher_Raw(HASHER_SHA3K, data, length, hash); + + ge25519_fromfe_frombytes_vartime(&point2, hash); + ge25519_mul8(P, &point2); +} + +void xmr_derivation_to_scalar(bignum256modm s, const ge25519* p, uint32_t output_index) { + uint8_t buff[32 + 8] = {0}; + ge25519_pack(buff, p); + int written = xmr_write_varint(buff + 32, 8, output_index); + xmr_hash_to_scalar(s, buff, 32u + written); +} + +void xmr_generate_key_derivation(ge25519* r, const ge25519* A, const bignum256modm b) { + ge25519 bA = {0}; + ge25519_scalarmult(&bA, A, b); + ge25519_mul8(r, &bA); +} + +void xmr_derive_private_key( + bignum256modm s, + const ge25519* deriv, + uint32_t idx, + const bignum256modm base) { + xmr_derivation_to_scalar(s, deriv, idx); + add256_modm(s, s, base); +} + +void xmr_derive_public_key(ge25519* r, const ge25519* deriv, uint32_t idx, const ge25519* base) { + bignum256modm s = {0}; + ge25519 p2 = {0}; + + xmr_derivation_to_scalar(s, deriv, idx); + ge25519_scalarmult_base_niels(&p2, ge25519_niels_base_multiples, s); + ge25519_add(r, base, &p2, 0); +} + +void xmr_add_keys2(ge25519* r, const bignum256modm a, const bignum256modm b, const ge25519* B) { + // aG + bB, G is basepoint + ge25519 aG = {0}, bB = {0}; + ge25519_scalarmult_base_niels(&aG, ge25519_niels_base_multiples, a); + ge25519_scalarmult(&bB, B, b); + ge25519_add(r, &aG, &bB, 0); +} + +void xmr_add_keys2_vartime( + ge25519* r, + const bignum256modm a, + const bignum256modm b, + const ge25519* B) { + // aG + bB, G is basepoint + ge25519_double_scalarmult_vartime(r, B, b, a); +} + +void xmr_add_keys3( + ge25519* r, + const bignum256modm a, + const ge25519* A, + const bignum256modm b, + const ge25519* B) { + // aA + bB + ge25519 aA = {0}, bB = {0}; + ge25519_scalarmult(&aA, A, a); + ge25519_scalarmult(&bB, B, b); + ge25519_add(r, &aA, &bB, 0); +} + +void xmr_add_keys3_vartime( + ge25519* r, + const bignum256modm a, + const ge25519* A, + const bignum256modm b, + const ge25519* B) { + // aA + bB + ge25519_double_scalarmult_vartime2(r, A, a, B, b); +} + +void xmr_get_subaddress_secret_key( + bignum256modm r, + uint32_t major, + uint32_t minor, + const bignum256modm m) { + const char prefix[] = "SubAddr"; + unsigned char buff[32] = {0}; + contract256_modm(buff, m); + + char data[sizeof(prefix) + sizeof(buff) + 2 * sizeof(uint32_t)] = {0}; + memcpy(data, prefix, sizeof(prefix)); + memcpy(data + sizeof(prefix), buff, sizeof(buff)); + +#if BYTE_ORDER == BIG_ENDIAN + REVERSE32(major, major); + REVERSE32(minor, minor); +#endif + + memcpy(data + sizeof(prefix) + sizeof(buff), &major, sizeof(uint32_t)); + memcpy(data + sizeof(prefix) + sizeof(buff) + sizeof(uint32_t), &minor, sizeof(uint32_t)); + + xmr_hash_to_scalar(r, data, sizeof(data)); +} + +void xmr_gen_c(ge25519* r, const bignum256modm a, uint64_t amount) { + // C = aG + bH + bignum256modm b = {0}; + set256_modm(b, amount); + xmr_add_keys2(r, a, b, &xmr_h); +} + +#endif // USE_MONERO diff --git a/applications/external/flipbip/lib/crypto/monero/xmr.h b/applications/external/flipbip/lib/crypto/monero/xmr.h new file mode 100644 index 000000000..16c2aec5e --- /dev/null +++ b/applications/external/flipbip/lib/crypto/monero/xmr.h @@ -0,0 +1,93 @@ +// +// Created by Dusan Klinec on 10/05/2018. +// + +#if USE_MONERO + +#ifndef TREZOR_CRYPTO_XMR_H +#define TREZOR_CRYPTO_XMR_H + +#include "../ed25519_donna/ed25519_donna.h" +#include "../hasher.h" + +extern const ge25519 ALIGN(16) xmr_h; + +typedef unsigned char xmr_key_t[32]; + +typedef struct xmr_ctkey { + xmr_key_t dest; + xmr_key_t mask; +} xmr_ctkey_t; + +/* sets H point to r */ +void ge25519_set_xmr_h(ge25519* r); + +/* random scalar value */ +void xmr_random_scalar(bignum256modm m); + +/* cn_fast_hash */ +void xmr_fast_hash(uint8_t* hash, const void* data, size_t length); + +/* incremental hashing wrappers */ +void xmr_hasher_init(Hasher* hasher); +void xmr_hasher_update(Hasher* hasher, const void* data, size_t length); +void xmr_hasher_final(Hasher* hasher, uint8_t* hash); +void xmr_hasher_copy(Hasher* dst, const Hasher* src); + +/* H_s(buffer) */ +void xmr_hash_to_scalar(bignum256modm r, const void* data, size_t length); + +/* H_p(buffer) */ +void xmr_hash_to_ec(ge25519* P, const void* data, size_t length); + +/* derivation to scalar value */ +void xmr_derivation_to_scalar(bignum256modm s, const ge25519* p, uint32_t output_index); + +/* derivation */ +void xmr_generate_key_derivation(ge25519* r, const ge25519* A, const bignum256modm b); + +/* H_s(derivation || varint(output_index)) + base */ +void xmr_derive_private_key( + bignum256modm s, + const ge25519* deriv, + uint32_t idx, + const bignum256modm base); + +/* H_s(derivation || varint(output_index))G + base */ +void xmr_derive_public_key(ge25519* r, const ge25519* deriv, uint32_t idx, const ge25519* base); + +/* aG + bB, G is basepoint */ +void xmr_add_keys2(ge25519* r, const bignum256modm a, const bignum256modm b, const ge25519* B); +void xmr_add_keys2_vartime( + ge25519* r, + const bignum256modm a, + const bignum256modm b, + const ge25519* B); + +/* aA + bB */ +void xmr_add_keys3( + ge25519* r, + const bignum256modm a, + const ge25519* A, + const bignum256modm b, + const ge25519* B); +void xmr_add_keys3_vartime( + ge25519* r, + const bignum256modm a, + const ge25519* A, + const bignum256modm b, + const ge25519* B); + +/* subaddress secret */ +void xmr_get_subaddress_secret_key( + bignum256modm r, + uint32_t major, + uint32_t minor, + const bignum256modm m); + +/* Generates Pedersen commitment C = aG + bH */ +void xmr_gen_c(ge25519* r, const bignum256modm a, uint64_t amount); + +#endif // TREZOR_CRYPTO_XMR_H + +#endif // USE_MONERO diff --git a/applications/external/flipbip/lib/crypto/nem.c b/applications/external/flipbip/lib/crypto/nem.c new file mode 100644 index 000000000..391c1e6fc --- /dev/null +++ b/applications/external/flipbip/lib/crypto/nem.c @@ -0,0 +1,603 @@ +/** + * Copyright (c) 2017 Saleem Rashid + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, E1PRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "options.h" + +#if USE_NEM + +#include "nem.h" + +#include + +#include "base32.h" +#include "ed25519_donna/ed25519_keccak.h" +#include "memzero.h" +#include "ripemd160.h" +#include "sha3.h" + +#define CAN_WRITE(NEEDED) ((ctx->offset + (NEEDED)) <= ctx->size) + +#define SERIALIZE_U32(DATA) \ + do { \ + if(!nem_write_u32(ctx, (DATA))) return false; \ + } while(0) +#define SERIALIZE_U64(DATA) \ + do { \ + if(!nem_write_u64(ctx, (DATA))) return false; \ + } while(0) +#define SERIALIZE_TAGGED(DATA, LENGTH) \ + do { \ + if(!nem_write_tagged(ctx, (DATA), (LENGTH))) return false; \ + } while(0) + +const char* nem_network_name(uint8_t network) { + switch(network) { + case NEM_NETWORK_MAINNET: + return "NEM Mainnet"; + case NEM_NETWORK_TESTNET: + return "NEM Testnet"; + case NEM_NETWORK_MIJIN: + return "Mijin"; + default: + return NULL; + } +} + +static inline bool + nem_write_checked(nem_transaction_ctx* ctx, const uint8_t* data, uint32_t length) { + if(!CAN_WRITE(length)) { + return false; + } + + memcpy(&ctx->buffer[ctx->offset], data, length); + ctx->offset += length; + return true; +} + +static inline bool nem_write_u32(nem_transaction_ctx* ctx, uint32_t data) { + if(!CAN_WRITE(4)) { + return false; + } + + ctx->buffer[ctx->offset++] = (data >> 0) & 0xff; + ctx->buffer[ctx->offset++] = (data >> 8) & 0xff; + ctx->buffer[ctx->offset++] = (data >> 16) & 0xff; + ctx->buffer[ctx->offset++] = (data >> 24) & 0xff; + + return true; +} + +static inline bool nem_write_u64(nem_transaction_ctx* ctx, uint64_t data) { + SERIALIZE_U32((data >> 0) & 0xffffffff); + SERIALIZE_U32((data >> 32) & 0xffffffff); + + return true; +} + +static inline bool + nem_write_tagged(nem_transaction_ctx* ctx, const uint8_t* data, uint32_t length) { + SERIALIZE_U32(length); + + return nem_write_checked(ctx, data, length); +} + +static inline bool + nem_write_mosaic_str(nem_transaction_ctx* ctx, const char* name, const char* value) { + uint32_t name_length = strlen(name); + uint32_t value_length = strlen(value); + + SERIALIZE_U32(sizeof(uint32_t) + name_length + sizeof(uint32_t) + value_length); + SERIALIZE_TAGGED((const uint8_t*)name, name_length); + SERIALIZE_TAGGED((const uint8_t*)value, value_length); + + return true; +} + +static inline bool nem_write_mosaic_bool(nem_transaction_ctx* ctx, const char* name, bool value) { + return nem_write_mosaic_str(ctx, name, value ? "true" : "false"); +} + +static inline bool + nem_write_mosaic_u64(nem_transaction_ctx* ctx, const char* name, uint64_t value) { + char buffer[21] = {0}; + + if(bn_format_uint64(value, NULL, NULL, 0, 0, false, 0, buffer, sizeof(buffer)) == 0) { + return false; + } + + return nem_write_mosaic_str(ctx, name, buffer); +} + +void nem_get_address_raw(const ed25519_public_key public_key, uint8_t version, uint8_t* address) { + uint8_t hash[SHA3_256_DIGEST_LENGTH] = {0}; + + /* 1. Perform 256-bit Sha3 on the public key */ + keccak_256(public_key, sizeof(ed25519_public_key), hash); + + /* 2. Perform 160-bit Ripemd of hash resulting from step 1. */ + ripemd160(hash, SHA3_256_DIGEST_LENGTH, &address[1]); + + /* 3. Prepend version byte to Ripemd hash (either 0x68 or 0x98) */ + address[0] = version; + + /* 4. Perform 256-bit Sha3 on the result, take the first four bytes as a + * checksum */ + keccak_256(address, 1 + RIPEMD160_DIGEST_LENGTH, hash); + + /* 5. Concatenate output of step 3 and the checksum from step 4 */ + memcpy(&address[1 + RIPEMD160_DIGEST_LENGTH], hash, 4); + + memzero(hash, sizeof(hash)); +} + +bool nem_get_address(const ed25519_public_key public_key, uint8_t version, char* address) { + uint8_t pubkeyhash[NEM_ADDRESS_SIZE_RAW] = {0}; + + nem_get_address_raw(public_key, version, pubkeyhash); + + char* ret = base32_encode( + pubkeyhash, sizeof(pubkeyhash), address, NEM_ADDRESS_SIZE + 1, BASE32_ALPHABET_RFC4648); + + memzero(pubkeyhash, sizeof(pubkeyhash)); + return (ret != NULL); +} + +bool nem_validate_address_raw(const uint8_t* address, uint8_t network) { + if(!nem_network_name(network) || address[0] != network) { + return false; + } + + uint8_t hash[SHA3_256_DIGEST_LENGTH] = {0}; + + keccak_256(address, 1 + RIPEMD160_DIGEST_LENGTH, hash); + bool valid = (memcmp(&address[1 + RIPEMD160_DIGEST_LENGTH], hash, 4) == 0); + + memzero(hash, sizeof(hash)); + return valid; +} + +bool nem_validate_address(const char* address, uint8_t network) { + uint8_t pubkeyhash[NEM_ADDRESS_SIZE_RAW] = {0}; + + if(strlen(address) != NEM_ADDRESS_SIZE) { + return false; + } + + uint8_t* ret = base32_decode( + address, NEM_ADDRESS_SIZE, pubkeyhash, sizeof(pubkeyhash), BASE32_ALPHABET_RFC4648); + bool valid = (ret != NULL) && nem_validate_address_raw(pubkeyhash, network); + + memzero(pubkeyhash, sizeof(pubkeyhash)); + return valid; +} + +void nem_transaction_start( + nem_transaction_ctx* ctx, + const ed25519_public_key public_key, + uint8_t* buffer, + size_t size) { + memcpy(ctx->public_key, public_key, sizeof(ctx->public_key)); + + ctx->buffer = buffer; + ctx->offset = 0; + ctx->size = size; +} + +size_t nem_transaction_end( + nem_transaction_ctx* ctx, + const ed25519_secret_key private_key, + ed25519_signature signature) { + if(private_key != NULL && signature != NULL) { + ed25519_sign_keccak(ctx->buffer, ctx->offset, private_key, signature); + } + + return ctx->offset; +} + +bool nem_transaction_write_common( + nem_transaction_ctx* ctx, + uint32_t type, + uint32_t version, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, + uint32_t deadline) { + SERIALIZE_U32(type); + SERIALIZE_U32(version); + SERIALIZE_U32(timestamp); + SERIALIZE_TAGGED(signer, sizeof(ed25519_public_key)); + SERIALIZE_U64(fee); + SERIALIZE_U32(deadline); + + return true; +} + +bool nem_transaction_create_transfer( + nem_transaction_ctx* ctx, + uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, + uint32_t deadline, + const char* recipient, + uint64_t amount, + const uint8_t* payload, + uint32_t length, + bool encrypted, + uint32_t mosaics) { + if(!signer) { + signer = ctx->public_key; + } + + if(!payload) { + length = 0; + } + + bool ret = nem_transaction_write_common( + ctx, + NEM_TRANSACTION_TYPE_TRANSFER, + (uint32_t)network << 24 | (mosaics ? 2 : 1), + timestamp, + signer, + fee, + deadline); + if(!ret) return false; + + SERIALIZE_TAGGED((const uint8_t*)recipient, NEM_ADDRESS_SIZE); + SERIALIZE_U64(amount); + + if(length) { + SERIALIZE_U32(sizeof(uint32_t) + sizeof(uint32_t) + length); + SERIALIZE_U32(encrypted ? 0x02 : 0x01); + SERIALIZE_TAGGED(payload, length); + } else { + SERIALIZE_U32(0); + } + + if(mosaics) { + SERIALIZE_U32(mosaics); + } + + return true; +} + +bool nem_transaction_write_mosaic( + nem_transaction_ctx* ctx, + const char* namespace, + const char* mosaic, + uint64_t quantity) { + size_t namespace_length = strlen(namespace); + size_t mosaic_length = strlen(mosaic); + size_t identifier_length = + sizeof(uint32_t) + namespace_length + sizeof(uint32_t) + mosaic_length; + + SERIALIZE_U32(sizeof(uint32_t) + sizeof(uint64_t) + identifier_length); + SERIALIZE_U32(identifier_length); + SERIALIZE_TAGGED((const uint8_t*)namespace, namespace_length); + SERIALIZE_TAGGED((const uint8_t*)mosaic, mosaic_length); + SERIALIZE_U64(quantity); + + return true; +} + +bool nem_transaction_create_multisig( + nem_transaction_ctx* ctx, + uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, + uint32_t deadline, + const nem_transaction_ctx* inner) { + if(!signer) { + signer = ctx->public_key; + } + + bool ret = nem_transaction_write_common( + ctx, + NEM_TRANSACTION_TYPE_MULTISIG, + (uint32_t)network << 24 | 1, + timestamp, + signer, + fee, + deadline); + if(!ret) return false; + + SERIALIZE_TAGGED(inner->buffer, inner->offset); + + return true; +} + +bool nem_transaction_create_multisig_signature( + nem_transaction_ctx* ctx, + uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, + uint32_t deadline, + const nem_transaction_ctx* inner) { + if(!signer) { + signer = ctx->public_key; + } + + bool ret = nem_transaction_write_common( + ctx, + NEM_TRANSACTION_TYPE_MULTISIG_SIGNATURE, + (uint32_t)network << 24 | 1, + timestamp, + signer, + fee, + deadline); + if(!ret) return false; + + char address[NEM_ADDRESS_SIZE + 1] = {0}; + nem_get_address(inner->public_key, network, address); + + uint8_t hash[SHA3_256_DIGEST_LENGTH] = {0}; + keccak_256(inner->buffer, inner->offset, hash); + + SERIALIZE_U32(sizeof(uint32_t) + SHA3_256_DIGEST_LENGTH); + SERIALIZE_TAGGED(hash, SHA3_256_DIGEST_LENGTH); + SERIALIZE_TAGGED((const uint8_t*)address, NEM_ADDRESS_SIZE); + + return true; +} + +bool nem_transaction_create_provision_namespace( + nem_transaction_ctx* ctx, + uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, + uint32_t deadline, + const char* namespace, + const char* parent, + const char* rental_sink, + uint64_t rental_fee) { + if(!signer) { + signer = ctx->public_key; + } + + bool ret = nem_transaction_write_common( + ctx, + NEM_TRANSACTION_TYPE_PROVISION_NAMESPACE, + (uint32_t)network << 24 | 1, + timestamp, + signer, + fee, + deadline); + if(!ret) return false; + + if(parent) { + SERIALIZE_TAGGED((const uint8_t*)rental_sink, NEM_ADDRESS_SIZE); + SERIALIZE_U64(rental_fee); + SERIALIZE_TAGGED((const uint8_t*)namespace, strlen(namespace)); + SERIALIZE_TAGGED((const uint8_t*)parent, strlen(parent)); + } else { + SERIALIZE_TAGGED((const uint8_t*)rental_sink, NEM_ADDRESS_SIZE); + SERIALIZE_U64(rental_fee); + SERIALIZE_TAGGED((const uint8_t*)namespace, strlen(namespace)); + SERIALIZE_U32(0xffffffff); + } + + return true; +} + +bool nem_transaction_create_mosaic_creation( + nem_transaction_ctx* ctx, + uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, + uint32_t deadline, + const char* namespace, + const char* mosaic, + const char* description, + uint32_t divisibility, + uint64_t supply, + bool mutable_supply, + bool transferable, + uint32_t levy_type, + uint64_t levy_fee, + const char* levy_address, + const char* levy_namespace, + const char* levy_mosaic, + const char* creation_sink, + uint64_t creation_fee) { + if(!signer) { + signer = ctx->public_key; + } + + bool ret = nem_transaction_write_common( + ctx, + NEM_TRANSACTION_TYPE_MOSAIC_CREATION, + (uint32_t)network << 24 | 1, + timestamp, + signer, + fee, + deadline); + if(!ret) return false; + + size_t namespace_length = strlen(namespace); + size_t mosaic_length = strlen(mosaic); + size_t identifier_length = + sizeof(uint32_t) + namespace_length + sizeof(uint32_t) + mosaic_length; + + // This length will be rewritten later on + nem_transaction_ctx state = {0}; + memcpy(&state, ctx, sizeof(state)); + + SERIALIZE_U32(0); + SERIALIZE_TAGGED(signer, sizeof(ed25519_public_key)); + SERIALIZE_U32(identifier_length); + SERIALIZE_TAGGED((const uint8_t*)namespace, namespace_length); + SERIALIZE_TAGGED((const uint8_t*)mosaic, mosaic_length); + SERIALIZE_TAGGED((const uint8_t*)description, strlen(description)); + SERIALIZE_U32(4); // Number of properties + + if(!nem_write_mosaic_u64(ctx, "divisibility", divisibility)) return false; + if(!nem_write_mosaic_u64(ctx, "initialSupply", supply)) return false; + if(!nem_write_mosaic_bool(ctx, "supplyMutable", mutable_supply)) return false; + if(!nem_write_mosaic_bool(ctx, "transferable", transferable)) return false; + + if(levy_type) { + size_t levy_namespace_length = strlen(levy_namespace); + size_t levy_mosaic_length = strlen(levy_mosaic); + size_t levy_identifier_length = + sizeof(uint32_t) + levy_namespace_length + sizeof(uint32_t) + levy_mosaic_length; + + SERIALIZE_U32( + sizeof(uint32_t) + sizeof(uint32_t) + NEM_ADDRESS_SIZE + sizeof(uint32_t) + + levy_identifier_length + sizeof(uint64_t)); + SERIALIZE_U32(levy_type); + SERIALIZE_TAGGED((const uint8_t*)levy_address, NEM_ADDRESS_SIZE); + SERIALIZE_U32(levy_identifier_length); + SERIALIZE_TAGGED((const uint8_t*)levy_namespace, levy_namespace_length); + SERIALIZE_TAGGED((const uint8_t*)levy_mosaic, levy_mosaic_length); + SERIALIZE_U64(levy_fee); + } else { + SERIALIZE_U32(0); + } + + // Rewrite length + nem_write_u32(&state, ctx->offset - state.offset - sizeof(uint32_t)); + + SERIALIZE_TAGGED((const uint8_t*)creation_sink, NEM_ADDRESS_SIZE); + SERIALIZE_U64(creation_fee); + + return true; +} + +bool nem_transaction_create_mosaic_supply_change( + nem_transaction_ctx* ctx, + uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, + uint32_t deadline, + const char* namespace, + const char* mosaic, + uint32_t type, + uint64_t delta) { + if(!signer) { + signer = ctx->public_key; + } + + bool ret = nem_transaction_write_common( + ctx, + NEM_TRANSACTION_TYPE_MOSAIC_SUPPLY_CHANGE, + (uint32_t)network << 24 | 1, + timestamp, + signer, + fee, + deadline); + if(!ret) return false; + + size_t namespace_length = strlen(namespace); + size_t mosaic_length = strlen(mosaic); + size_t identifier_length = + sizeof(uint32_t) + namespace_length + sizeof(uint32_t) + mosaic_length; + + SERIALIZE_U32(identifier_length); + SERIALIZE_TAGGED((const uint8_t*)namespace, namespace_length); + SERIALIZE_TAGGED((const uint8_t*)mosaic, mosaic_length); + SERIALIZE_U32(type); + SERIALIZE_U64(delta); + + return true; +} + +bool nem_transaction_create_aggregate_modification( + nem_transaction_ctx* ctx, + uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, + uint32_t deadline, + uint32_t modifications, + bool relative_change) { + if(!signer) { + signer = ctx->public_key; + } + + bool ret = nem_transaction_write_common( + ctx, + NEM_TRANSACTION_TYPE_AGGREGATE_MODIFICATION, + (uint32_t)network << 24 | (relative_change ? 2 : 1), + timestamp, + signer, + fee, + deadline); + if(!ret) return false; + + SERIALIZE_U32(modifications); + + return true; +} + +bool nem_transaction_write_cosignatory_modification( + nem_transaction_ctx* ctx, + uint32_t type, + const ed25519_public_key cosignatory) { + SERIALIZE_U32(sizeof(uint32_t) + sizeof(uint32_t) + sizeof(ed25519_public_key)); + SERIALIZE_U32(type); + SERIALIZE_TAGGED(cosignatory, sizeof(ed25519_public_key)); + + return true; +} + +bool nem_transaction_write_minimum_cosignatories(nem_transaction_ctx* ctx, int32_t relative_change) { + SERIALIZE_U32(sizeof(uint32_t)); + SERIALIZE_U32((uint32_t)relative_change); + + return true; +} + +bool nem_transaction_create_importance_transfer( + nem_transaction_ctx* ctx, + uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, + uint32_t deadline, + uint32_t mode, + const ed25519_public_key remote) { + if(!signer) { + signer = ctx->public_key; + } + + bool ret = nem_transaction_write_common( + ctx, + NEM_TRANSACTION_TYPE_IMPORTANCE_TRANSFER, + (uint32_t)network << 24 | 1, + timestamp, + signer, + fee, + deadline); + if(!ret) return false; + + SERIALIZE_U32(mode); + SERIALIZE_TAGGED(remote, sizeof(ed25519_public_key)); + + return true; +} + +#endif // USE_NEM diff --git a/applications/external/flipbip/lib/crypto/nem.h b/applications/external/flipbip/lib/crypto/nem.h new file mode 100644 index 000000000..38b7530d7 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/nem.h @@ -0,0 +1,216 @@ +/** + * Copyright (c) 2017 Saleem Rashid + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "../options.h" + +#if USE_NEM + +#ifndef __NEM_H__ +#define __NEM_H__ + +#include +#include +#include + +#include "bip32.h" +#include "ed25519_donna/ed25519.h" + +#define NEM_LEVY_PERCENTILE_DIVISOR 4 +#define NEM_MAX_DIVISIBILITY 6 +#define NEM_MAX_SUPPLY 9000000000 + +#define NEM_NETWORK_MAINNET 0x68 +#define NEM_NETWORK_TESTNET 0x98 +#define NEM_NETWORK_MIJIN 0x60 + +#define NEM_ADDRESS_SIZE 40 +#define NEM_ADDRESS_SIZE_RAW 25 + +#define NEM_TRANSACTION_TYPE_TRANSFER 0x0101 +#define NEM_TRANSACTION_TYPE_IMPORTANCE_TRANSFER 0x0801 +#define NEM_TRANSACTION_TYPE_AGGREGATE_MODIFICATION 0x1001 +#define NEM_TRANSACTION_TYPE_MULTISIG_SIGNATURE 0x1002 +#define NEM_TRANSACTION_TYPE_MULTISIG 0x1004 +#define NEM_TRANSACTION_TYPE_PROVISION_NAMESPACE 0x2001 +#define NEM_TRANSACTION_TYPE_MOSAIC_CREATION 0x4001 +#define NEM_TRANSACTION_TYPE_MOSAIC_SUPPLY_CHANGE 0x4002 + +#define NEM_SALT_SIZE sizeof(ed25519_public_key) + +#define NEM_ENCRYPTED_SIZE(size) (((size) + AES_BLOCK_SIZE) / AES_BLOCK_SIZE * AES_BLOCK_SIZE) +#define NEM_ENCRYPTED_PAYLOAD_SIZE(size) \ + (AES_BLOCK_SIZE + NEM_SALT_SIZE + NEM_ENCRYPTED_SIZE(size)) + +#define _NEM_PADDING_SIZE(buffer, size) ((buffer)[(size)-1]) +#define NEM_PADDING_SIZE(buffer, size) \ + (_NEM_PADDING_SIZE(buffer, size) > (size) ? (size) : _NEM_PADDING_SIZE(buffer, size)) + +#define NEM_DECRYPTED_SIZE(buffer, size) ((size)-NEM_PADDING_SIZE(buffer, size)) + +typedef struct { + ed25519_public_key public_key; + uint8_t* buffer; + size_t offset; + size_t size; +} nem_transaction_ctx; + +const char* nem_network_name(uint8_t network); + +void nem_get_address_raw(const ed25519_public_key public_key, uint8_t version, uint8_t* address); +bool nem_get_address(const ed25519_public_key public_key, uint8_t version, char* address); + +bool nem_validate_address_raw(const uint8_t* address, uint8_t network); +bool nem_validate_address(const char* address, uint8_t network); + +void nem_transaction_start( + nem_transaction_ctx* ctx, + const ed25519_public_key public_key, + uint8_t* buffer, + size_t size); +size_t nem_transaction_end( + nem_transaction_ctx* ctx, + const ed25519_secret_key private_key, + ed25519_signature signature); + +bool nem_transaction_write_common( + nem_transaction_ctx* context, + uint32_t type, + uint32_t version, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, + uint32_t deadline); + +bool nem_transaction_create_transfer( + nem_transaction_ctx* context, + uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, + uint32_t deadline, + const char* recipient, + uint64_t amount, + const uint8_t* payload, + uint32_t length, + bool encrypted, + uint32_t mosaics); + +bool nem_transaction_write_mosaic( + nem_transaction_ctx* ctx, + const char* namespace, + const char* mosaic, + uint64_t quantity); + +bool nem_transaction_create_multisig( + nem_transaction_ctx* ctx, + uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, + uint32_t deadline, + const nem_transaction_ctx* inner); + +bool nem_transaction_create_multisig_signature( + nem_transaction_ctx* ctx, + uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, + uint32_t deadline, + const nem_transaction_ctx* inner); + +bool nem_transaction_create_provision_namespace( + nem_transaction_ctx* ctx, + uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, + uint32_t deadline, + const char* namespace, + const char* parent, + const char* rental_sink, + uint64_t rental_fee); + +bool nem_transaction_create_mosaic_creation( + nem_transaction_ctx* ctx, + uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, + uint32_t deadline, + const char* namespace, + const char* mosaic, + const char* description, + uint32_t divisibility, + uint64_t supply, + bool mutable_supply, + bool transferable, + uint32_t levy_type, + uint64_t levy_fee, + const char* levy_address, + const char* levy_namespace, + const char* levy_mosaic, + const char* creation_sink, + uint64_t creation_fee); + +bool nem_transaction_create_mosaic_supply_change( + nem_transaction_ctx* ctx, + uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, + uint32_t deadline, + const char* namespace, + const char* mosaic, + uint32_t type, + uint64_t delta); + +bool nem_transaction_create_aggregate_modification( + nem_transaction_ctx* ctx, + uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, + uint32_t deadline, + uint32_t modifications, + bool relative_change); + +bool nem_transaction_write_cosignatory_modification( + nem_transaction_ctx* ctx, + uint32_t type, + const ed25519_public_key cosignatory); + +bool nem_transaction_write_minimum_cosignatories(nem_transaction_ctx* ctx, int32_t relative_change); + +bool nem_transaction_create_importance_transfer( + nem_transaction_ctx* ctx, + uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, + uint32_t deadline, + uint32_t mode, + const ed25519_public_key remote); + +#endif + +#endif // USE_NEM diff --git a/applications/external/flipbip/lib/crypto/nist256p1.c b/applications/external/flipbip/lib/crypto/nist256p1.c new file mode 100644 index 000000000..51dc569cd --- /dev/null +++ b/applications/external/flipbip/lib/crypto/nist256p1.c @@ -0,0 +1,114 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "nist256p1.h" + +const ecdsa_curve nist256p1 = { + /* .prime */ {/*.val =*/{ + 0x1fffffff, + 0x1fffffff, + 0x1fffffff, + 0x000001ff, + 0x00000000, + 0x00000000, + 0x00040000, + 0x1fe00000, + 0xffffff}}, + + /* G */ + {/*.x =*/{/*.val =*/{ + 0x1898c296, + 0x0509ca2e, + 0x1acce83d, + 0x06fb025b, + 0x040f2770, + 0x1372b1d2, + 0x091fe2f3, + 0x1e5c2588, + 0x6b17d1}}, + /*.y =*/{/*.val =*/{ + 0x17bf51f5, + 0x1db20341, + 0x0c57b3b2, + 0x1c66aed6, + 0x19e162bc, + 0x15a53e07, + 0x1e6e3b9f, + 0x1c5fc34f, + 0x4fe342}}}, + + /* order */ + {/*.val =*/{ + 0x1c632551, + 0x1dce5617, + 0x05e7a13c, + 0x0df55b4e, + 0x1ffffbce, + 0x1fffffff, + 0x0003ffff, + 0x1fe00000, + 0xffffff}}, + + /* order_half */ + {/*.val =*/{ + 0x1e3192a8, + 0x0ee72b0b, + 0x02f3d09e, + 0x06faada7, + 0x1ffffde7, + 0x1fffffff, + 0x0001ffff, + 0x1ff00000, + 0x7fffff}}, + + /* a */ -3, + + /* b */ + {/*.val =*/{ + 0x07d2604b, + 0x1e71e1f1, + 0x14ec3d8e, + 0x1a0d6198, + 0x086bc651, + 0x1eaabb4c, + 0x0f9ecfae, + 0x1b154752, + 0x005ac635}} + +#if USE_PRECOMPUTED_CP + , + /* cp */ + { +#include "nist256p1.table" + } +#endif +}; + +const curve_info nist256p1_info = { + .bip32_name = "Nist256p1 seed", + .params = &nist256p1, + .hasher_base58 = HASHER_SHA2D, + .hasher_sign = HASHER_SHA2D, + .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_script = HASHER_SHA2, +}; diff --git a/applications/external/flipbip/lib/crypto/nist256p1.h b/applications/external/flipbip/lib/crypto/nist256p1.h new file mode 100644 index 000000000..02d04025a --- /dev/null +++ b/applications/external/flipbip/lib/crypto/nist256p1.h @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __NIST256P1_H__ +#define __NIST256P1_H__ + +#include + +#include "bip32.h" +#include "ecdsa.h" + +extern const ecdsa_curve nist256p1; +extern const curve_info nist256p1_info; + +#endif diff --git a/applications/external/flipbip/lib/crypto/nist256p1.table b/applications/external/flipbip/lib/crypto/nist256p1.table new file mode 100644 index 000000000..6be01b4d6 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/nist256p1.table @@ -0,0 +1,1664 @@ + { + /* 1*16^0*G: */ + {{{0x1898c296, 0x0509ca2e, 0x1acce83d, 0x06fb025b, 0x040f2770, 0x1372b1d2, 0x091fe2f3, 0x1e5c2588, 0x6b17d1}}, + {{0x17bf51f5, 0x1db20341, 0x0c57b3b2, 0x1c66aed6, 0x19e162bc, 0x15a53e07, 0x1e6e3b9f, 0x1c5fc34f, 0x4fe342}}}, + /* 3*16^0*G: */ + {{{0x06e7fd6c, 0x1a0b30de, 0x0b6a617e, 0x0d6e43df, 0x1f165e6c, 0x17ca8ea5, 0x091323df, 0x1a34c661, 0x5ecbe4}}, + {{0x027d5032, 0x13cd893d, 0x13ee0f66, 0x15606c70, 0x0a2ecd82, 0x03670d32, 0x1df8dd2c, 0x0189331f, 0x873464}}}, + /* 5*16^0*G: */ + {{{0x03d033ed, 0x0aaa506e, 0x16f94908, 0x1905fa3e, 0x08fdfef8, 0x042b0433, 0x034b5e13, 0x0f4a2a28, 0x51590b}}, + {{0x1da16da4, 0x0e85da27, 0x16022234, 0x025e01a9, 0x079260d0, 0x1f9b5fc5, 0x09f62b86, 0x1512094e, 0xe0c17d}}}, + /* 7*16^0*G: */ + {{{0x1187b2a3, 0x00314381, 0x03fbd6cc, 0x13f17150, 0x1fb607ef, 0x18333e00, 0x0d1896ec, 0x0df417ef, 0x8e533b}}, + {{0x01f400b4, 0x0af0d436, 0x0106c871, 0x0e6c6796, 0x1900053c, 0x0fc1d37a, 0x00d9b41a, 0x17bc0663, 0x73eb1d}}}, + /* 9*16^0*G: */ + {{{0x10949ee0, 0x1cf4525c, 0x1b7e2cf5, 0x15971858, 0x1f8729e0, 0x1c6a8eb8, 0x0dc61e24, 0x16dfdbe1, 0xea68d7}}, + {{0x0dd048fa, 0x02d11252, 0x17a08ffa, 0x029fd549, 0x0a0c84d7, 0x054b2547, 0x139e1c05, 0x192e593f, 0x2a2744}}}, + /* 11*16^0*G: */ + {{{0x14bc21d1, 0x199c8e9b, 0x14122fd0, 0x085da04a, 0x01cda167, 0x1bced861, 0x116418e0, 0x16f10769, 0x3ed113}}, + {{0x082a3740, 0x17c777e7, 0x062276b8, 0x1a09b4bd, 0x0c68a090, 0x01d7d27a, 0x02889321, 0x13599899, 0x909920}}}, + /* 13*16^0*G: */ + {{{0x06072c01, 0x070aecea, 0x1ab562a6, 0x1c5096cb, 0x0e2fc792, 0x0ef96c2f, 0x05698601, 0x0f5c1589, 0x177c83}}, + {{0x0fc7bfd8, 0x021ddf17, 0x1ed37ce7, 0x1c298743, 0x14e7226e, 0x08d6da07, 0x15628902, 0x19a9d7d4, 0x63bb58}}}, + /* 15*16^0*G: */ + {{{0x059b9d5f, 0x1b34631f, 0x0e83bc58, 0x075f25bc, 0x08265ae0, 0x1bc4ccc4, 0x0b9eb7ec, 0x18d2e357, 0xf0454d}}, + {{0x0d034f36, 0x1f2ce6f0, 0x0d7e8fd1, 0x16439ceb, 0x043e62a3, 0x0a728fcb, 0x147d3996, 0x1c6b25c5, 0xb5b93e}}} + }, + { + /* 1*16^1*G: */ + {{{0x01277c6e, 0x0f5a3c3f, 0x1b280e29, 0x10725dfe, 0x0315fcd2, 0x0e314c1b, 0x06162e08, 0x02714d68, 0x76a94d}}, + {{0x0b8c5110, 0x14eeeb92, 0x11e2ea83, 0x1340081f, 0x08720859, 0x10daf08f, 0x1839b2c2, 0x0c2683e4, 0xa985fe}}}, + /* 3*16^1*G: */ + {{{0x1e4536ca, 0x1fdcee34, 0x0806986a, 0x1d252c14, 0x0cda11c2, 0x1a2df038, 0x07b23339, 0x01c924a7, 0x9482fb}}, + {{0x158cc1c8, 0x1d6c31df, 0x01efeec7, 0x1abc52ae, 0x14e63f63, 0x11c653a9, 0x1fe46975, 0x14e8be2a, 0x351d9c}}}, + /* 5*16^1*G: */ + {{{0x15ecff13, 0x0d8ed714, 0x1418cf12, 0x0c9439b7, 0x01eeb637, 0x0d28a984, 0x04656e0d, 0x182f5d26, 0xb2e1b7}}, + {{0x12187d44, 0x1dd24c4d, 0x17a8b9a8, 0x1435302f, 0x158c387d, 0x10d1556b, 0x0f33c8ce, 0x0262747d, 0xe6c044}}}, + /* 7*16^1*G: */ + {{{0x0ef87286, 0x05dd99a7, 0x08c2790e, 0x07d0fbf8, 0x0ee34070, 0x0bbee5e3, 0x0f0b2cd0, 0x05cfe36d, 0xb43346}}, + {{0x041496d9, 0x16023fb4, 0x0b3a92de, 0x1c4100d4, 0x12e6f9dc, 0x073960b4, 0x17f8e0fd, 0x0a4dda56, 0xa0da54}}}, + /* 9*16^1*G: */ + {{{0x19794381, 0x1cc35ad8, 0x0c31d806, 0x02b10ebd, 0x07b19189, 0x1482daab, 0x0933061b, 0x19c9a7b4, 0xa47420}}, + {{0x02769c52, 0x0b671d3f, 0x1dab1e1a, 0x0b811b73, 0x07afff3a, 0x1c9b0ccb, 0x1f839cf7, 0x1bef7c37, 0x2ebbff}}}, + /* 11*16^1*G: */ + {{{0x09a5185a, 0x03a23324, 0x179bcafb, 0x0e15913e, 0x1a3195b8, 0x0a009586, 0x05217fb3, 0x03373a12, 0x5ba7a}}, + {{0x01de3a4e, 0x0a1e4470, 0x016b8005, 0x0c441792, 0x1d48e760, 0x011f1271, 0x025b919e, 0x16bd0583, 0x30e0d2}}}, + /* 13*16^1*G: */ + {{{0x199b85fe, 0x151cc5af, 0x0e977f56, 0x1dfd355c, 0x1e0b79c0, 0x06c8c041, 0x0bf5a5e6, 0x193a1bfc, 0xb29f74}}, + {{0x0da604dc, 0x1d3214bb, 0x1d67a036, 0x1ec7a617, 0x1c6d92de, 0x18974b6b, 0x1e175741, 0x1874d852, 0xa3ce5b}}}, + /* 15*16^1*G: */ + {{{0x07e030ef, 0x1b3a2b74, 0x1543a589, 0x16560af9, 0x02b08576, 0x1f81f924, 0x13d41db2, 0x15517237, 0x99299b}}, + {{0x18d9aa9a, 0x0c735bee, 0x10021113, 0x0258933e, 0x0aa7957c, 0x0080d367, 0x1862fcce, 0x1a6667f1, 0x5cc2e3}}} + }, + { + /* 1*16^2*G: */ + {{{0x12d0441b, 0x0d971af8, 0x1a95930b, 0x1a16e21a, 0x1ed61190, 0x08a94301, 0x19661fff, 0x14760122, 0x34a2d4}}, + {{0x1e93b146, 0x01273c22, 0x1776076d, 0x0ecd73bd, 0x17fc0e7d, 0x1882373b, 0x0f08af29, 0x0d4a743c, 0xbeaaed}}}, + /* 3*16^2*G: */ + {{{0x1da08424, 0x0725719d, 0x1d912a77, 0x1f6f56e9, 0x123ed3ab, 0x02ffd4ae, 0x06a86d63, 0x00f5b86b, 0xa98b0a}}, + {{0x0831800c, 0x10943d07, 0x17d60b4d, 0x17d01741, 0x11320752, 0x0f46470e, 0x0d9b94c6, 0x08e44933, 0x4754c6}}}, + /* 5*16^2*G: */ + {{{0x083c2d6a, 0x096bf2f4, 0x0f4a6ced, 0x1f231b03, 0x0696dd22, 0x15bc642d, 0x0b17486d, 0x013911b5, 0xa034f0}}, + {{0x02c30e72, 0x019b7796, 0x099f9f3d, 0x0c06be2c, 0x0eb06be0, 0x1c2a2e76, 0x107ec336, 0x06d95133, 0xfe1b00}}}, + /* 7*16^2*G: */ + {{{0x08be8c78, 0x0b528ee9, 0x1e4f935c, 0x12d9f056, 0x0e9a14a0, 0x115a04b1, 0x100681db, 0x1fe633a8, 0xb52226}}, + {{0x11686903, 0x019b3e52, 0x0d63fcc8, 0x1eff91cb, 0x0851a819, 0x1b34bf49, 0x1503286c, 0x193ea73e, 0x701ee0}}}, + /* 9*16^2*G: */ + {{{0x0058b5a4, 0x0207f205, 0x0c65e6dc, 0x08c9f0f2, 0x04713de4, 0x07667e66, 0x16cf65a3, 0x0c30d1c0, 0xa3e388}}, + {{0x07113aef, 0x19836c87, 0x1c68a523, 0x1d08b76e, 0x1e68f3ce, 0x1359d74b, 0x04b0e123, 0x110fbe1a, 0xcfd457}}}, + /* 11*16^2*G: */ + {{{0x04a08314, 0x02faf648, 0x11f7fde8, 0x1c6db65b, 0x1197a82f, 0x055cd110, 0x14e4ccf3, 0x094263f4, 0x209954}}, + {{0x07573ccc, 0x1fc64e2f, 0x1f3fa5b9, 0x0dcb4e6d, 0x048dfd40, 0x1472e5c8, 0x0c6243ee, 0x1fa55467, 0xa5cf3d}}}, + /* 13*16^2*G: */ + {{{0x09078c18, 0x017fca57, 0x1b7a4a54, 0x018795dd, 0x1d39b99e, 0x1739556f, 0x11c0c23d, 0x0275981d, 0x751d65}}, + {{0x0ece0d67, 0x0c6b74ae, 0x1816b1e6, 0x12918397, 0x02a4ef00, 0x05d7b515, 0x056214d5, 0x1fb94948, 0xba9c3f}}}, + /* 15*16^2*G: */ + {{{0x1e86d900, 0x167e6ae4, 0x08f6d124, 0x1dc13a2f, 0x03b36405, 0x0184501d, 0x00445ed2, 0x044b88f0, 0x5be0f5}}, + {{0x158a5755, 0x066eb4df, 0x0cd3d6b1, 0x02e4a483, 0x1423df92, 0x11d273da, 0x108b4d1f, 0x1cdbfe58, 0x83d1d9}}} + }, + { + /* 1*16^3*G: */ + {{{0x0245573f, 0x03bf46d5, 0x1f42993c, 0x0cede5e9, 0x16bd2508, 0x04b39736, 0x193665de, 0x1a59e0d3, 0xe716ae}}, + {{0x069218d1, 0x02fe135a, 0x01f26cd4, 0x1a1be5f4, 0x1a851d13, 0x183343dc, 0x0aad644a, 0x1cd29f8e, 0x353663}}}, + /* 3*16^3*G: */ + {{{0x057008ac, 0x1cc3c983, 0x0a7b7edf, 0x1c3d9dc6, 0x1a22d19c, 0x0ac5260e, 0x13a19395, 0x11adea0f, 0xd2bf89}}, + {{0x127beb55, 0x088a9a53, 0x1fc1e620, 0x19c2156b, 0x10c56679, 0x0aed9fd4, 0x1ea8fe06, 0x196b4d6e, 0x69c0b1}}}, + /* 5*16^3*G: */ + {{{0x182f1580, 0x086be54b, 0x080fadff, 0x09bbdc48, 0x064f8b0e, 0x0b9c8f98, 0x19821fe9, 0x09dcb079, 0x4d8830}}, + {{0x1616edd7, 0x007d8b6a, 0x1ac78443, 0x19477ad1, 0x16518aaf, 0x00044c7e, 0x0db3a35a, 0x0e13560c, 0x28a94e}}}, + /* 7*16^3*G: */ + {{{0x00c38e11, 0x1c261ed7, 0x1b89ae97, 0x0c8437d4, 0x1af9e715, 0x1cc90172, 0x1bacc99c, 0x04f91f81, 0x17c727}}, + {{0x0e90decd, 0x0c1b35dd, 0x0336b8f3, 0x07328b4c, 0x1802e7e5, 0x17e67480, 0x0cf10180, 0x1e9fccc9, 0x95c5a4}}}, + /* 9*16^3*G: */ + {{{0x032f36ea, 0x0aafec57, 0x0d5070f6, 0x1e8d4e52, 0x0b8b3cd4, 0x18e7e426, 0x02a2118e, 0x15588e8a, 0x7e03fd}}, + {{0x0a68b8af, 0x16611fe4, 0x140275a2, 0x1d2f3498, 0x0af99419, 0x158b80c2, 0x03699a39, 0x1e240245, 0xdcf6d5}}}, + /* 11*16^3*G: */ + {{{0x1953baa9, 0x01f29536, 0x18637a35, 0x0b5d0c93, 0x0b214261, 0x1d60ee50, 0x1c1d858d, 0x0d096379, 0x8ce6da}}, + {{0x152689e5, 0x073ae147, 0x0a4d075e, 0x0730d76d, 0x1b56807f, 0x1de48030, 0x082f9a6c, 0x171f5262, 0x3d9f4f}}}, + /* 13*16^3*G: */ + {{{0x0f22a96a, 0x15c6c29d, 0x1aae3e52, 0x03753b38, 0x0e2b008b, 0x1aa4badd, 0x15288294, 0x06081b80, 0xb570e7}}, + {{0x085d1b00, 0x199fb30e, 0x15732732, 0x1376f4b0, 0x0cfbda7c, 0x1bb4dae0, 0x1dfc0a30, 0x0c71ee3c, 0xdcd8a2}}}, + /* 15*16^3*G: */ + {{{0x189a7509, 0x12075ca2, 0x1ea01527, 0x0e172c83, 0x1f20de12, 0x0d1f3ae3, 0x10ec1284, 0x04797572, 0x44d943}}, + {{0x00437234, 0x10515cdb, 0x137449b8, 0x07c3fbe2, 0x193586f9, 0x1de693bd, 0x1c280d08, 0x10010803, 0xb2c5b3}}} + }, + { + /* 1*16^4*G: */ + {{{0x0eade3c4, 0x1f4232e3, 0x014a8140, 0x156e9392, 0x186b4714, 0x1219a072, 0x04363971, 0x0de9d23d, 0xa01836}}, + {{0x0b26e8d0, 0x02e21013, 0x1853cdfd, 0x0e509c88, 0x18369d5f, 0x12bc1a4e, 0x0c59f1b3, 0x02e28221, 0xe2bbec}}}, + /* 3*16^4*G: */ + {{{0x19e0af06, 0x10e6f562, 0x1b65635b, 0x07314ac5, 0x1055c92f, 0x1dad36a2, 0x059142f4, 0x001711b1, 0x9cdf1f}}, + {{0x0216ade7, 0x0bd196db, 0x1f2951a3, 0x0a45b832, 0x194b0828, 0x05de6e46, 0x15993656, 0x1fda7e55, 0x916d25}}}, + /* 5*16^4*G: */ + {{{0x1305097e, 0x09b95c9c, 0x0ee94660, 0x0c2e1d08, 0x0448338d, 0x0d9682a0, 0x0fb6adac, 0x1aba34cc, 0x45bfd9}}, + {{0x108ddc04, 0x05d02c74, 0x14b05655, 0x173a677f, 0x0e908683, 0x0182a386, 0x14aeeb62, 0x0250ab5f, 0x9d1dc}}}, + /* 7*16^4*G: */ + {{{0x163bd6df, 0x098f8d05, 0x19abb0f3, 0x184785ba, 0x15e6fd1f, 0x0fce0144, 0x04ed9c7a, 0x02ac8ecd, 0xb599ad}}, + {{0x0efa09ac, 0x150e751c, 0x04d2d163, 0x0189ed22, 0x1c4166a4, 0x1b05c591, 0x0cc918dc, 0x1bd89f56, 0x6979d1}}}, + /* 9*16^4*G: */ + {{{0x07142d62, 0x1c309f99, 0x0ef09b6b, 0x14d46bf0, 0x054c11d9, 0x158913f4, 0x103a4998, 0x1e2ce655, 0xf4dca1}}, + {{0x1a618fc9, 0x04f66603, 0x134f5feb, 0x0f359dfb, 0x1c659bb9, 0x1c0dc8d5, 0x151b527c, 0x1cb69699, 0x551167}}}, + /* 11*16^4*G: */ + {{{0x015fae61, 0x1658ffa3, 0x0e57e087, 0x0b8fb89e, 0x0bb5a7f1, 0x1120738b, 0x0d9b6713, 0x141cdc13, 0xf07278}}, + {{0x096376f9, 0x1e865ba4, 0x0dfaaf3d, 0x0e0e2b70, 0x0f7d42c2, 0x10410c4c, 0x1a97df5e, 0x056294e3, 0x1a681b}}}, + /* 13*16^4*G: */ + {{{0x0466591f, 0x027020a9, 0x11a35a83, 0x0e5d51ff, 0x058ccbe1, 0x15a99dd4, 0x16c3c50e, 0x0af5e141, 0x1fc524}}, + {{0x196f8cdb, 0x077f7ab9, 0x1b1e0891, 0x11958465, 0x14e1629f, 0x1b7f2da1, 0x1047a7b1, 0x070113d7, 0x489c18}}}, + /* 15*16^4*G: */ + {{{0x122a8ebc, 0x12e85c61, 0x1e59c544, 0x039b6e31, 0x056d5a29, 0x05ad9865, 0x17d3f5fc, 0x16634918, 0xfa2501}}, + {{0x0a8a775b, 0x06c93dad, 0x0f20cc60, 0x11c11cd9, 0x1a8cbea5, 0x0f330d37, 0x0588ce14, 0x1629f0b1, 0x71c932}}} + }, + { + /* 1*16^5*G: */ + {{{0x1d96dff1, 0x1bee765b, 0x157f3fa3, 0x08638355, 0x198d530e, 0x105ab866, 0x153ffbda, 0x10a283fc, 0xec738}}, + {{0x1c7b552c, 0x16420d63, 0x1b5e2aa7, 0x04c99d0f, 0x052511d5, 0x0277ac03, 0x1d7646b3, 0x09d0f5d0, 0xd6224f}}}, + /* 3*16^5*G: */ + {{{0x088d58e9, 0x0e192558, 0x18c60e14, 0x14b838c9, 0x0a7b6e94, 0x12353e21, 0x0a1ba64a, 0x1fb8e0c9, 0x96dac3}}, + {{0x0ebebc5e, 0x01a49895, 0x01f9b8e0, 0x17d13729, 0x0c439685, 0x024a49c1, 0x06b615b3, 0x1e75a8d8, 0xcb1faf}}}, + /* 5*16^5*G: */ + {{{0x0db29f92, 0x0a956899, 0x11ecb162, 0x03a4e372, 0x18f811d2, 0x0e1bc575, 0x0c4a8417, 0x079d629e, 0xe297b2}}, + {{0x05e58ddb, 0x0794a645, 0x1b505058, 0x079d770b, 0x19149122, 0x0dd5dc66, 0x02d2d203, 0x041f196e, 0xe13725}}}, + /* 7*16^5*G: */ + {{{0x0ad88c33, 0x0ca1dbdc, 0x1d1af2bf, 0x15c729b2, 0x0da97d91, 0x1e490692, 0x12d9ac1a, 0x071f6572, 0x1cd223}}, + {{0x048fb1b2, 0x14753c21, 0x12879258, 0x1ca262bd, 0x0bc2713f, 0x1205589b, 0x02c25b21, 0x1f071569, 0xfc3acd}}}, + /* 9*16^5*G: */ + {{{0x1b26aa73, 0x09d644e1, 0x18e8383d, 0x0fc23618, 0x11ee0cdf, 0x16986ffd, 0x0eff2c72, 0x15b73d3f, 0xf462d7}}, + {{0x18479e73, 0x02f560bb, 0x140b3289, 0x11c14600, 0x13c7a49e, 0x1d253439, 0x0c50354e, 0x034f068a, 0x406a0d}}}, + /* 11*16^5*G: */ + {{{0x1cd015e3, 0x170f0155, 0x194089cf, 0x01d2b2fc, 0x15168af9, 0x1f59e544, 0x12bdd6f6, 0x04ba7ee1, 0xe0f689}}, + {{0x12157cce, 0x15126a16, 0x0a4daef6, 0x116a723c, 0x0c77c55b, 0x14b6393a, 0x0aa54d89, 0x0621c907, 0x8531e}}}, + /* 13*16^5*G: */ + {{{0x0bb76b12, 0x1362188a, 0x0649da47, 0x1cecee7c, 0x15a00ea8, 0x1598957b, 0x15ff0760, 0x182aa57e, 0x28e4ad}}, + {{0x0c4747bd, 0x1f229d3f, 0x058a3fd5, 0x014c1e2e, 0x0a3f703a, 0x1b2db5cf, 0x06cfd392, 0x09dfb340, 0x14d74c}}}, + /* 15*16^5*G: */ + {{{0x076ff697, 0x1fac00ff, 0x01d918a2, 0x16d10ca4, 0x097c6369, 0x16d5d9d0, 0x017b49c7, 0x04f29750, 0x85a0ba}}, + {{0x12142721, 0x04f6a6d2, 0x02962e4c, 0x12fff4f2, 0x1aa551de, 0x0869ee76, 0x0929551e, 0x0c3d587c, 0xadf32e}}} + }, + { + /* 1*16^6*G: */ + {{{0x0392d805, 0x192e2ee7, 0x1501750d, 0x1500d30e, 0x1449aa87, 0x06d57d51, 0x0f5e9295, 0x19e98d52, 0xf8f5dc}}, + {{0x0cda02fa, 0x1330ca8b, 0x0850ee80, 0x07b4c94a, 0x1327351f, 0x1f19b230, 0x0150e274, 0x19ecdac6, 0xe58176}}}, + /* 3*16^6*G: */ + {{{0x1fa046f7, 0x0ea598b3, 0x01cc2746, 0x021e7204, 0x02d45171, 0x05644a37, 0x0ea53821, 0x0950cb10, 0xe12c8e}}, + {{0x012646ad, 0x1d2ad145, 0x0c464d14, 0x1809c226, 0x126f6dd0, 0x1f6a9c98, 0x0bcd0cec, 0x0c21fb34, 0x7cec04}}}, + /* 5*16^6*G: */ + {{{0x02853c43, 0x0d893f46, 0x08b919ae, 0x0cd8af5c, 0x13236481, 0x1177f1e8, 0x0824f423, 0x0e82f2d2, 0x394bd4}}, + {{0x0064469d, 0x0bc14665, 0x03f3c32c, 0x1ece25b2, 0x00767d52, 0x1fe178eb, 0x1ae481f8, 0x0a42a3b8, 0x2b4d6d}}}, + /* 7*16^6*G: */ + {{{0x1c722e94, 0x016eb9cf, 0x0162587b, 0x102072da, 0x004334ed, 0x132b62ca, 0x0ba51171, 0x1be71bd0, 0xca8538}}, + {{0x1049a527, 0x105316f8, 0x02c9a90e, 0x12a75149, 0x19f12f20, 0x189350fd, 0x170c479c, 0x085d73c0, 0x3b27fc}}}, + /* 9*16^6*G: */ + {{{0x1cad6309, 0x18ba314e, 0x0e7fd221, 0x143f85e4, 0x07b3dd31, 0x1a312653, 0x0dd686ed, 0x0b3e46af, 0x663e1a}}, + {{0x09981f28, 0x19435d1c, 0x1ad4af54, 0x0fa88805, 0x0f918b90, 0x00c1e58e, 0x030f040b, 0x07700cd5, 0x292fb7}}}, + /* 11*16^6*G: */ + {{{0x02c23d03, 0x13ad9229, 0x11ffc924, 0x03609b1f, 0x1eeab3ba, 0x1611b83d, 0x19c25b0d, 0x1ce60c6c, 0xa2d9ef}}, + {{0x1085db74, 0x01726027, 0x0e77d144, 0x134fd2b0, 0x01b92ea0, 0x021b6388, 0x0e3c554c, 0x05199083, 0x1cc852}}}, + /* 13*16^6*G: */ + {{{0x07d4c6d1, 0x1aafcb38, 0x167ffec5, 0x059aa335, 0x135d0f66, 0x085a939f, 0x07bf82e4, 0x05691635, 0x5657e1}}, + {{0x0106bdec, 0x0181f94c, 0x14b05062, 0x1346b428, 0x06a0abff, 0x1c8799d7, 0x07e6b3ec, 0x1e971ba9, 0x72b5be}}}, + /* 15*16^6*G: */ + {{{0x1933564a, 0x032a6eaa, 0x18ebd13e, 0x1169f5db, 0x18d2b7a6, 0x16e333b6, 0x00042193, 0x02ba815c, 0x5b6862}}, + {{0x0204ef63, 0x1af822c4, 0x1e21a7ce, 0x15dc4510, 0x195de392, 0x062a68ce, 0x19154b4c, 0x0d39e744, 0x76b5ea}}} + }, + { + /* 1*16^7*G: */ + {{{0x0f922dbd, 0x025118bb, 0x064863e6, 0x0c622c3f, 0x171b91ca, 0x1556c726, 0x1cc4fe17, 0x17ffa9b5, 0x6d28b6}}, + {{0x00ef3cff, 0x055ff815, 0x1368a651, 0x09d3e170, 0x14a1c4c2, 0x10d30e65, 0x0be903ef, 0x00a283ba, 0xaf39d9}}}, + /* 3*16^7*G: */ + {{{0x1b168b64, 0x0c86ffcc, 0x01b2102d, 0x07a0558b, 0x0467ea15, 0x0482fe0a, 0x0f774f7c, 0x0f4ff7fc, 0x7cd315}}, + {{0x1abbb16b, 0x0b60695a, 0x180b8d61, 0x189b36e5, 0x1fafb13a, 0x073c5e6d, 0x1188815a, 0x0422e525, 0x9ca08d}}}, + /* 5*16^7*G: */ + {{{0x06ef29e8, 0x158e37d0, 0x166bb8ec, 0x18aa9613, 0x1356264d, 0x018ccea2, 0x03115ac9, 0x1b6be5bf, 0xed860b}}, + {{0x19b90f8f, 0x00d0e24d, 0x036a8cd4, 0x061eb85b, 0x17bb1e76, 0x1b59a020, 0x1ff5f1af, 0x086ebab4, 0xb837e7}}}, + /* 7*16^7*G: */ + {{{0x1636e617, 0x0fc8c59f, 0x1c73d667, 0x19a07783, 0x12c9d47d, 0x0e173f13, 0x090dcd78, 0x11fa3a42, 0x6868cc}}, + {{0x1cbb3d27, 0x046ee79f, 0x0e1335c7, 0x1c619148, 0x13f0a60f, 0x081c3c98, 0x079acf16, 0x14b7237f, 0xeed008}}}, + /* 9*16^7*G: */ + {{{0x113e2a34, 0x1ced1530, 0x0e8478b1, 0x1a5ccb9c, 0x1d318291, 0x1a4f8857, 0x1880b172, 0x0c1d591f, 0xec03b3}}, + {{0x184566d6, 0x01121f75, 0x084dade9, 0x102adccb, 0x122728aa, 0x0f108090, 0x010defbf, 0x1f6c140b, 0x86020f}}}, + /* 11*16^7*G: */ + {{{0x087c1b18, 0x1570672e, 0x12646897, 0x1c596a90, 0x056fa101, 0x01ad2c88, 0x04379a8c, 0x1473cf17, 0xa79464}}, + {{0x1b94809a, 0x15ac284b, 0x158a086f, 0x11bd38e2, 0x089f60d9, 0x0bc3cf4d, 0x03309269, 0x1c7ee50b, 0x1361f4}}}, + /* 13*16^7*G: */ + {{{0x1ed10d26, 0x0a714636, 0x19657d96, 0x157df053, 0x10ccc5a9, 0x0fdb4a79, 0x131e43a4, 0x101551f7, 0x544ef2}}, + {{0x16dafcc2, 0x1e127b93, 0x0b01ab8b, 0x1adf2edc, 0x170d3683, 0x0eff46c6, 0x0b3a75ac, 0x13b88b58, 0x95b91c}}}, + /* 15*16^7*G: */ + {{{0x17ad18e6, 0x04a3cfc5, 0x0f2b5789, 0x1a7cf31a, 0x0ff9b57a, 0x1e4235a5, 0x18853794, 0x110be698, 0xe2c26c}}, + {{0x0554cfad, 0x0d7f28d5, 0x0607792b, 0x0a2b94e3, 0x1ba113bc, 0x1337508b, 0x06214738, 0x0509e910, 0xb2121b}}} + }, + { + /* 1*16^8*G: */ + {{{0x185a5943, 0x12d4f110, 0x1977ed8e, 0x12326cb8, 0x071da1ab, 0x15991316, 0x1e248595, 0x0815e455, 0x7fe36b}}, + {{0x099ca101, 0x0868a963, 0x02bc84b5, 0x07ab0cf7, 0x0a6f174b, 0x1a0203ee, 0x18927c27, 0x0b04b6c6, 0xe697d4}}}, + /* 3*16^8*G: */ + {{{0x1f0922a8, 0x153c048e, 0x173e365d, 0x01d3a4a8, 0x18b808e9, 0x072b0117, 0x15ce0249, 0x080b69c5, 0x4b656a}}, + {{0x199a80bb, 0x0d6e562c, 0x0143da53, 0x0773c573, 0x0c4d6d47, 0x06612aec, 0x00e48341, 0x03a25cef, 0xee1ea3}}}, + /* 5*16^8*G: */ + {{{0x09d07e9e, 0x0827c443, 0x09830dad, 0x1cf943ed, 0x18e5ea09, 0x15f07d9e, 0x04f64f6c, 0x0dd7acbc, 0x9d7895}}, + {{0x03d8c8ee, 0x06eb0ad6, 0x0531ecbd, 0x0145b477, 0x010ce746, 0x144e0e99, 0x0335950a, 0x0dde91d5, 0xd5149e}}}, + /* 7*16^8*G: */ + {{{0x1dc4950f, 0x13ba8433, 0x0e5081d9, 0x03655b7a, 0x16316574, 0x1423726d, 0x1ea55c8d, 0x0e5c26a7, 0x4acb12}}, + {{0x03d8b4df, 0x16372223, 0x019ab159, 0x1c85016b, 0x1e29fdf9, 0x0c7b6638, 0x16b633ca, 0x01f6e879, 0x726cd2}}}, + /* 9*16^8*G: */ + {{{0x0d7e8cbd, 0x0063d3df, 0x01f605bd, 0x0cff15e0, 0x1464a2a6, 0x09aa8640, 0x1ed08d11, 0x17e34d62, 0x640c5e}}, + {{0x1ec5a5db, 0x171481e5, 0x1fe6c081, 0x0d3f6319, 0x0ab9eba0, 0x0375b80f, 0x14bcaba7, 0x1fb0539f, 0xd6ae88}}}, + /* 11*16^8*G: */ + {{{0x1e86bddc, 0x18502583, 0x1738f57d, 0x04d72f2e, 0x16b9bf1d, 0x116486ed, 0x0cc91455, 0x16368509, 0x8bba04}}, + {{0x09e349c4, 0x111e2d0f, 0x065b97d4, 0x19fbc9e8, 0x1437ac6a, 0x1c90b34c, 0x1afd966f, 0x18138411, 0xc34099}}}, + /* 13*16^8*G: */ + {{{0x0257f582, 0x0b873c02, 0x10e89634, 0x1213d5bd, 0x05fe41f9, 0x0a1fbe2d, 0x1f88429a, 0x089fd9a6, 0x8b0a57}}, + {{0x17372d4b, 0x00bff6f9, 0x0581d992, 0x168d74f6, 0x17d4656d, 0x0ad09bf1, 0x1ce598a8, 0x09d81ad8, 0x9e57a4}}}, + /* 15*16^8*G: */ + {{{0x185e797e, 0x18a24fcc, 0x0f0c5a0f, 0x1c449e5c, 0x078a6f06, 0x17a49ecb, 0x025c7e15, 0x12f84c8f, 0xa13ff}}, + {{0x139d666f, 0x193d5cfa, 0x0030e4a0, 0x1ede14eb, 0x1dc3ff27, 0x00c747d0, 0x0f5645f6, 0x09644b90, 0xeb1a96}}} + }, + { + /* 1*16^9*G: */ + {{{0x1dde3445, 0x17fa7f0f, 0x0ba9e05e, 0x1753bb45, 0x0519e76b, 0x0ff3ff93, 0x079a14dc, 0x0709ae0c, 0x6965b6}}, + {{0x18855113, 0x0621c4f0, 0x17e6765f, 0x19cc0a34, 0x12dbef47, 0x04b31c39, 0x1444c979, 0x1c738904, 0xd1bcda}}}, + /* 3*16^9*G: */ + {{{0x088acfc5, 0x0f207cb4, 0x1a25e27d, 0x1eb1366c, 0x11a71b1e, 0x1eedea04, 0x1f6809f9, 0x03bbceb8, 0xe1cbc5}}, + {{0x0249a225, 0x1e2ff6ad, 0x0fee948e, 0x065257dd, 0x1e23ce7d, 0x1b27fedc, 0x0bb6cc49, 0x12f9bcfb, 0xec6783}}}, + /* 5*16^9*G: */ + {{{0x0107ccc6, 0x0c7529ff, 0x0f208a1d, 0x112fc2a8, 0x100481d3, 0x0e9422d4, 0x0a85cc7a, 0x0f2e2271, 0x9c3f26}}, + {{0x1dea9152, 0x003ca669, 0x1e6c61a1, 0x11fa9d2b, 0x06eca51a, 0x1afa5f9f, 0x16722f8d, 0x036c96a3, 0xdaee0c}}}, + /* 7*16^9*G: */ + {{{0x15a449e7, 0x0e2f5a1c, 0x0f0af908, 0x054069ca, 0x0922b2fa, 0x160bd8a0, 0x15c9e5be, 0x0aef8d65, 0x5c30d9}}, + {{0x0e2677d0, 0x1875240d, 0x139e439d, 0x1c80a787, 0x192d0b75, 0x12fbcce2, 0x0e48592d, 0x16b611c3, 0x8025e3}}}, + /* 9*16^9*G: */ + {{{0x0b8ceb07, 0x12ac6014, 0x1b89c73e, 0x124a57ff, 0x0d995537, 0x11583f54, 0x1a0abf93, 0x046191d2, 0xaa3bbf}}, + {{0x1fd83984, 0x0d423174, 0x0cfe7ae6, 0x036578f5, 0x162ec3b7, 0x187f2648, 0x09a11372, 0x161383d8, 0xe6320c}}}, + /* 11*16^9*G: */ + {{{0x03bfd1f1, 0x00752aac, 0x1595ccb9, 0x0db86a2b, 0x001943a3, 0x07e4c8a0, 0x0605e798, 0x0a226668, 0xab4a32}}, + {{0x08e1c233, 0x089cb086, 0x07a633c8, 0x1b26484f, 0x1e057a57, 0x1de82097, 0x19a2d3ac, 0x17606d90, 0xea6c64}}}, + /* 13*16^9*G: */ + {{{0x0b1d6d3f, 0x02036bc0, 0x1baee242, 0x0ecd149d, 0x1a8105f3, 0x1fae6c52, 0x15dfdccd, 0x0b3bbdab, 0xdba9b2}}, + {{0x09cd8133, 0x01749414, 0x0af64f31, 0x1b3788a2, 0x1871448b, 0x0ca7a7f5, 0x0ded6b2a, 0x07eaea6b, 0xb3862d}}}, + /* 15*16^9*G: */ + {{{0x11fa2a6a, 0x1cd01c01, 0x0392c959, 0x183ab0b6, 0x1cdfe34f, 0x0ba158d1, 0x1d141eb7, 0x1885d304, 0x1998f4}}, + {{0x06415142, 0x03f6da5e, 0x1c962d58, 0x180470f6, 0x0a1e94c6, 0x1c0045bc, 0x08425c03, 0x0da3215f, 0x2ebb41}}} + }, + { + /* 1*16^10*G: */ + {{{0x0d9aefbd, 0x0c7e5362, 0x0e55dd49, 0x1c8f64e7, 0x043dc1ef, 0x0f86a0de, 0x15d8cb2a, 0x03918cd3, 0xfbc34}}, + {{0x13e71ca0, 0x09db754e, 0x02a7fc7b, 0x160d3c40, 0x1d3d3950, 0x058ea4ab, 0x18ff9005, 0x0c65e6c1, 0xbd8022}}}, + /* 3*16^10*G: */ + {{{0x09434837, 0x1cb6fff7, 0x08306ee1, 0x0628170c, 0x1b06dadb, 0x0e37fda7, 0x0bb6c4d0, 0x1578950f, 0xd76d18}}, + {{0x1b215b4c, 0x1d5027cd, 0x0df33093, 0x08b1ceeb, 0x1933290a, 0x010a7bd5, 0x19137839, 0x1465db2c, 0xf6bc4d}}}, + /* 5*16^10*G: */ + {{{0x1c07f222, 0x1744f90c, 0x183f9f40, 0x0438c758, 0x153d1c5e, 0x0e8d0f8b, 0x1d813d20, 0x0a0c2cff, 0xd5c0c6}}, + {{0x0c6ffd57, 0x177b48f0, 0x004ea1b8, 0x07ea34f1, 0x175b9baf, 0x063bfa4f, 0x02143378, 0x10c102f7, 0x15a30b}}}, + /* 7*16^10*G: */ + {{{0x0e93bfa6, 0x1238b512, 0x084d8a92, 0x1a52b413, 0x09fe0d39, 0x05d335a6, 0x18b39527, 0x09c948de, 0x734c36}}, + {{0x18d10774, 0x037d3ccc, 0x00a5f13f, 0x026c4112, 0x05f48eca, 0x00f1a906, 0x141277a6, 0x007554f3, 0x99515}}}, + /* 9*16^10*G: */ + {{{0x1fa194ae, 0x075a8bfa, 0x0152bb3c, 0x00523b34, 0x0b149064, 0x0ece954f, 0x0a24045d, 0x1b40f6cd, 0x79a3d9}}, + {{0x1fcf634b, 0x1e32f4e4, 0x1e6f1353, 0x084be65e, 0x103d86bd, 0x18dc2c57, 0x06cd2cd9, 0x194e4a96, 0x84e1db}}}, + /* 11*16^10*G: */ + {{{0x01e8b7fe, 0x16483001, 0x016c9a9a, 0x01c5c2ef, 0x098e05dd, 0x06556e7e, 0x160a28f9, 0x0129ab60, 0x3393fd}}, + {{0x023c6821, 0x00a12210, 0x06e52dc3, 0x0d661515, 0x0668d8e5, 0x1576ce2d, 0x1ae0babf, 0x17d90cf7, 0x130437}}}, + /* 13*16^10*G: */ + {{{0x01528cf6, 0x04abceab, 0x141a53a8, 0x004a15ec, 0x10a52e6a, 0x02c3772d, 0x1f85786d, 0x10c268c4, 0xa16b28}}, + {{0x1ce93f3b, 0x05c907cf, 0x132004e0, 0x07f79027, 0x150f4349, 0x16bcec08, 0x166644f3, 0x15d0a6f5, 0xf40598}}}, + /* 15*16^10*G: */ + {{{0x0c8db2e0, 0x0885335c, 0x035cd60d, 0x197b82be, 0x074f6473, 0x04d5d4ad, 0x1d32fdb2, 0x04031c68, 0xd317ce}}, + {{0x074bc9a9, 0x0d9a5159, 0x0e183ce9, 0x04e9a045, 0x19136caa, 0x01f471cb, 0x112e670b, 0x01521270, 0xd61a21}}} + }, + { + /* 1*16^11*G: */ + {{{0x03fe67b2, 0x1718cbd5, 0x0b8cce31, 0x117fce14, 0x123b234a, 0x15cdd4b9, 0x1772f199, 0x086ee790, 0x6608c2}}, + {{0x05b47a28, 0x091ff2e7, 0x1150c206, 0x162b3e81, 0x0e03fc22, 0x1206d3a3, 0x05a211bd, 0x17d8a438, 0xa1a916}}}, + /* 3*16^11*G: */ + {{{0x0bc73e02, 0x1f375569, 0x194c4b04, 0x0cc29dd6, 0x18631849, 0x0c08beab, 0x108c81aa, 0x1c54d8bb, 0xf0956a}}, + {{0x0611219d, 0x0967b4cc, 0x0ba515cb, 0x1a091b77, 0x19356672, 0x02c57941, 0x00f1db88, 0x0c02289c, 0x433fe6}}}, + /* 5*16^11*G: */ + {{{0x1c5fe45c, 0x0f116f28, 0x1f03d65f, 0x05035070, 0x1283488b, 0x124ebe7b, 0x183294bc, 0x1d479454, 0xdb98eb}}, + {{0x1ef45a22, 0x05380e21, 0x12038711, 0x06409f54, 0x12c8ce98, 0x094eec48, 0x168b7854, 0x016eb7b0, 0xe0c0f3}}}, + /* 7*16^11*G: */ + {{{0x02128eac, 0x1acf306f, 0x0bc732eb, 0x0eb1ab99, 0x051690c4, 0x159dbeb5, 0x17d086e9, 0x02c15bb4, 0xa73c0}}, + {{0x04f1180d, 0x02c948eb, 0x1576728e, 0x0eb3e2ee, 0x10a7c793, 0x1b6eca7a, 0x0e329572, 0x0ac089d0, 0x443fda}}}, + /* 9*16^11*G: */ + {{{0x03ccbc30, 0x12d4998b, 0x0d258631, 0x1fcba43a, 0x197249ed, 0x1bb33d04, 0x1c8dc3b4, 0x1868f969, 0x378720}}, + {{0x1315729e, 0x110193f8, 0x0d23e11a, 0x19f2aba2, 0x19b6d16b, 0x05605553, 0x0e324c46, 0x1739ee4a, 0x8f1bdd}}}, + /* 11*16^11*G: */ + {{{0x03bb1b6b, 0x12546f2a, 0x1f0afea9, 0x1fde65e8, 0x1a621575, 0x08c6082a, 0x09867660, 0x03b6f163, 0xfe8fd2}}, + {{0x10eaaf93, 0x1daecdd1, 0x0afe2265, 0x09bb9fe1, 0x113c00f1, 0x074afad6, 0x18dda78a, 0x15d864ad, 0x791e22}}}, + /* 13*16^11*G: */ + {{{0x144b7cea, 0x002acce5, 0x1b3e1f7a, 0x08d28122, 0x1dcca474, 0x00113c59, 0x18bba081, 0x1aaf3f6f, 0x2c331f}}, + {{0x15d1c9c2, 0x1e15a356, 0x0c2501df, 0x04a23fe2, 0x1d650619, 0x19ec61de, 0x19dbf3cf, 0x0399c0c3, 0x20567b}}}, + /* 15*16^11*G: */ + {{{0x0112278c, 0x1c94d9bc, 0x03668563, 0x02c93a15, 0x04b66dd0, 0x1a643fc2, 0x0c828d22, 0x0d88ca34, 0x509bc0}}, + {{0x0e178f66, 0x043ae4c4, 0x0d7e517b, 0x0bfd0dce, 0x164570f6, 0x1a78bdc7, 0x1bb05d83, 0x1856e448, 0xb4b168}}} + }, + { + /* 1*16^12*G: */ + {{{0x17e55104, 0x175d7c00, 0x03a71c70, 0x1506bf77, 0x1561cf73, 0x09e1a6c5, 0x1cdd8f7a, 0x0a44f6f0, 0xd8de76}}, + {{0x052e08cd, 0x10177c07, 0x1036c6ca, 0x0e7f9c32, 0x0f924c2f, 0x114568ee, 0x0b457131, 0x0cb7c27e, 0x2fd294}}}, + /* 3*16^12*G: */ + {{{0x0987bfd3, 0x09ce163f, 0x110a131a, 0x0a8e5fe9, 0x1d19187c, 0x1df57d6e, 0x18cd5477, 0x0df7aa31, 0xe3a578}}, + {{0x0cc23e7d, 0x1698db64, 0x0a38205f, 0x19e5d9b2, 0x0210ca3d, 0x1cffa56c, 0x039a11de, 0x012a6b08, 0xf74bad}}}, + /* 5*16^12*G: */ + {{{0x02d5056e, 0x13ca8e91, 0x11e81f2d, 0x196b4fc4, 0x05e480ed, 0x0ffe74b7, 0x03504549, 0x083d94a4, 0x42a970}}, + {{0x10f7db11, 0x020a6e45, 0x07f47f52, 0x1c907add, 0x03b26b64, 0x16e935ab, 0x1c19bb0d, 0x0cd9e010, 0xf2fc7f}}}, + /* 7*16^12*G: */ + {{{0x13dafd3b, 0x13a2fc8e, 0x12ce55b1, 0x1133e05b, 0x179d66fb, 0x16176b29, 0x1933f88c, 0x036384f2, 0xd6ca7}}, + {{0x1a6fe6e8, 0x156f8a10, 0x021dc6b5, 0x049157dd, 0x1de58a02, 0x0a501383, 0x04f67f92, 0x1671fbc5, 0xa85130}}}, + /* 9*16^12*G: */ + {{{0x11131f8b, 0x15fce3ff, 0x0883537d, 0x08d2c19f, 0x11fb4696, 0x116fce21, 0x0f65f530, 0x0f5b0cb4, 0x5edca}}, + {{0x1a6f779f, 0x167858cd, 0x1a275243, 0x04a00be1, 0x071be335, 0x0b8daf81, 0x1af00727, 0x03c91d10, 0x9e5888}}}, + /* 11*16^12*G: */ + {{{0x0b597e4d, 0x047cfa0f, 0x1f468c67, 0x09e64bce, 0x11c11497, 0x02d19dbb, 0x0290486d, 0x0ac178f4, 0x5a13c0}}, + {{0x041856e0, 0x1bf2434f, 0x04d9992b, 0x1d0f56b2, 0x173ce7bd, 0x0c507916, 0x1ffd47f4, 0x027121f2, 0xc9e73c}}}, + /* 13*16^12*G: */ + {{{0x0260faf0, 0x153c4b0a, 0x1a564d76, 0x17a68b2f, 0x1272ea2b, 0x070d3407, 0x19d50c51, 0x0ac02f6d, 0x96b256}}, + {{0x0366d412, 0x07212907, 0x1f53d6b0, 0x177f30e0, 0x199e1890, 0x072b99df, 0x12b002b6, 0x1400366f, 0xdcf8a6}}}, + /* 15*16^12*G: */ + {{{0x0ad13276, 0x04d0df25, 0x1010f1e9, 0x06a1d5d3, 0x171a3ca6, 0x15959c3b, 0x18909bc4, 0x0218839b, 0xb9719}}, + {{0x0a84dadb, 0x19c79a10, 0x1c3eb8ec, 0x1af25304, 0x0811f593, 0x122d9dfb, 0x1bef538b, 0x0dde00dd, 0xac2848}}} + }, + { + /* 1*16^13*G: */ + {{{0x071e5c83, 0x1535e490, 0x10a82fbb, 0x04fe330a, 0x0e5b18bd, 0x02db952c, 0x1cfc82a1, 0x082a04da, 0x54ccc9}}, + {{0x140916a1, 0x1e8477b8, 0x03b925b3, 0x1c1798bb, 0x0bf22929, 0x038aed69, 0x14c8ea3e, 0x08b68a28, 0x1c433f}}}, + /* 3*16^13*G: */ + {{{0x0f76167c, 0x02f1b115, 0x1d19ce53, 0x1e845988, 0x0d9f22f2, 0x163496e6, 0x1e54e708, 0x1b96e7df, 0x87582e}}, + {{0x0f4d7ff6, 0x037ddb0b, 0x065efa1b, 0x051e0cee, 0x036a8880, 0x0161e1b9, 0x09eff784, 0x06a15ac9, 0x75b94}}}, + /* 5*16^13*G: */ + {{{0x14de6611, 0x1391f743, 0x0087ec11, 0x0cae7297, 0x0f11e33f, 0x1b9b1ab3, 0x1b6c7096, 0x1943e4e6, 0x4a107a}}, + {{0x18a805fe, 0x1ac75f72, 0x084cab00, 0x1aa8f4b8, 0x0052e075, 0x12747b80, 0x1ce4d339, 0x0a200c7d, 0x809b26}}}, + /* 7*16^13*G: */ + {{{0x0dcfecb0, 0x05d27683, 0x0a3611bf, 0x07fa3a61, 0x149f6e98, 0x0706a4df, 0x1f259528, 0x166e555b, 0xfd402e}}, + {{0x0da08de8, 0x02c9f9ef, 0x19979e44, 0x1698497b, 0x1a86b1a4, 0x131c4dd5, 0x088ba698, 0x061bb4c7, 0xd6b340}}}, + /* 9*16^13*G: */ + {{{0x154659ed, 0x1a6eb07a, 0x17659b96, 0x1c7a4432, 0x1d0a07fa, 0x0703ff64, 0x145577ee, 0x08c8c30e, 0x467bb3}}, + {{0x0800cf83, 0x1903e859, 0x004f8026, 0x17821b9a, 0x02cd3701, 0x06ac36dc, 0x03a287cb, 0x1a0b552f, 0xd01eff}}}, + /* 11*16^13*G: */ + {{{0x1c97e515, 0x1324c256, 0x021697fb, 0x09ad8673, 0x0c7e5691, 0x0db1874f, 0x0391b21e, 0x11f19bb8, 0xcf66b9}}, + {{0x006c8a51, 0x0c10a754, 0x0400cea5, 0x00e8b1b3, 0x06a7b33f, 0x1a081a76, 0x04847096, 0x0f72088c, 0xa7071}}}, + /* 13*16^13*G: */ + {{{0x186154e5, 0x1d295080, 0x0be8374e, 0x0054cd35, 0x06770864, 0x04a9d6a4, 0x08d1d472, 0x18c1f7f5, 0x3d9252}}, + {{0x1603a8a2, 0x1fe49fb4, 0x1f75c1dd, 0x03f6faf8, 0x14cf3aea, 0x19a144b5, 0x15ff1124, 0x1b9a5f53, 0x3d0d01}}}, + /* 15*16^13*G: */ + {{{0x0a4a8daa, 0x1db1db15, 0x029728f4, 0x00c01de5, 0x0968ce51, 0x1ada47a5, 0x1a71d83a, 0x164d112e, 0x2bbe38}}, + {{0x1236e49b, 0x1043ba74, 0x1adb9f5f, 0x056749c7, 0x00850990, 0x1f7c8fcb, 0x0dbd78b3, 0x1ec01a76, 0xf85707}}} + }, + { + /* 1*16^14*G: */ + {{{0x02d32936, 0x187dbb89, 0x011fc070, 0x19a05c65, 0x17f38e40, 0x03e8a89e, 0x11f67db3, 0x0b2f0294, 0xc5440c}}, + {{0x07cabfd4, 0x1217d1ba, 0x19079766, 0x0da50c63, 0x0f4acd8a, 0x0f0e91f6, 0x1e9cbb70, 0x174707c3, 0xd27ee9}}}, + /* 3*16^14*G: */ + {{{0x1989a8e1, 0x0c280f63, 0x1b92f75f, 0x1b2de6e9, 0x0fe0a7c1, 0x1023cdce, 0x1e6dd403, 0x188b9bf4, 0x3e4d03}}, + {{0x041c240a, 0x03c89c42, 0x0f59d026, 0x1e31abe7, 0x0a719ffa, 0x0be56be5, 0x11d6ab04, 0x1a102b4c, 0x12f744}}}, + /* 5*16^14*G: */ + {{{0x19bb7902, 0x09cd4686, 0x0df1cfda, 0x04d8e50d, 0x05e9fd8c, 0x124f4a24, 0x00d66a68, 0x09367ac2, 0x1b684}}, + {{0x003ee653, 0x0bfa258f, 0x00d9a0b3, 0x164c08e3, 0x11581fce, 0x0c72e1b6, 0x10f82fc6, 0x143d26f3, 0xe59063}}}, + /* 7*16^14*G: */ + {{{0x0371d9fe, 0x14dab6a6, 0x0675aef0, 0x166ad833, 0x13a4cf04, 0x0ad3e1d5, 0x1288cd65, 0x16359993, 0x952c3c}}, + {{0x0189a13f, 0x1b673692, 0x0231d7b5, 0x08c9e230, 0x0e5d0664, 0x089b7b76, 0x1c1a9f7e, 0x08defac5, 0x59b985}}}, + /* 9*16^14*G: */ + {{{0x0bc2c885, 0x03ffe3b4, 0x19395f21, 0x03dceea4, 0x1cde5155, 0x002285cb, 0x1ab21626, 0x1c2b62cd, 0xdfcb4e}}, + {{0x1345d92e, 0x0ea53218, 0x0afa5d5d, 0x0e7128f7, 0x00f411c7, 0x1e136416, 0x0e854f13, 0x12aaa0c2, 0x536a23}}}, + /* 11*16^14*G: */ + {{{0x1510208e, 0x1c5c295f, 0x15e50e1c, 0x199c5b09, 0x097bbdb8, 0x179d023e, 0x00322a1e, 0x18137cca, 0x157966}}, + {{0x0d207357, 0x10777128, 0x1690f7f5, 0x1f8c8865, 0x0be07008, 0x1bdbddc6, 0x193aaf7f, 0x0b56e244, 0x40446d}}}, + /* 13*16^14*G: */ + {{{0x0b96fe13, 0x04fe65f4, 0x014baa07, 0x0495a769, 0x16e23e49, 0x147fc09f, 0x042b5b86, 0x078963d3, 0xc6b21e}}, + {{0x17bb1417, 0x0035cb57, 0x19b4b5a8, 0x0aa122f3, 0x128a2ff6, 0x1c0f1a75, 0x1523952d, 0x1b186669, 0x335bcd}}}, + /* 15*16^14*G: */ + {{{0x03936565, 0x1b2c0cd6, 0x1fe931f0, 0x0f66db2e, 0x122d997a, 0x054ea9ca, 0x05bc2d2f, 0x188f18e5, 0xa231e4}}, + {{0x15ec5f19, 0x172b5031, 0x1c5509a2, 0x0adc012d, 0x1cf942ba, 0x07634401, 0x1a470365, 0x117d8ff7, 0x80e0c9}}} + }, + { + /* 1*16^15*G: */ + {{{0x1066fd48, 0x1cfa0b95, 0x05c560ef, 0x0e203971, 0x0dca61c3, 0x0dcbd35d, 0x07141b1e, 0x0f4844fe, 0x241c56}}, + {{0x12857b08, 0x1be9633c, 0x08d9815f, 0x10e2715d, 0x003a48ea, 0x00be0219, 0x152e4d8e, 0x127a8605, 0x40a62d}}}, + /* 3*16^15*G: */ + {{{0x0df9591d, 0x10fbedc8, 0x0d320aa1, 0x18758485, 0x07218dce, 0x09e25599, 0x03a72e83, 0x07704d2f, 0xde2fd2}}, + {{0x0457ad84, 0x070cb9e8, 0x100da92d, 0x15143f11, 0x12ebbda9, 0x1bf6425c, 0x0fcc17b2, 0x02676c48, 0x400d71}}}, + /* 5*16^15*G: */ + {{{0x1562282c, 0x15412a57, 0x1ef0ddcb, 0x1e75f271, 0x11340f02, 0x04581270, 0x0f7664e5, 0x16060999, 0x8df889}}, + {{0x01d195cd, 0x12b55ecb, 0x1e6ec55c, 0x1ee0899d, 0x0f35e247, 0x0f318c45, 0x1bb5b1d0, 0x0ce640b9, 0x74525b}}}, + /* 7*16^15*G: */ + {{{0x0dddb2dd, 0x0ea944a8, 0x0b0369be, 0x10c99b98, 0x0f245078, 0x1c0678a9, 0x03e0007e, 0x119b3170, 0xa0fd75}}, + {{0x13ede6b2, 0x1eca7fc3, 0x10269f1f, 0x19d2df12, 0x08f311c8, 0x0fe989d8, 0x0357e1a4, 0x06b8266d, 0x53e5d8}}}, + /* 9*16^15*G: */ + {{{0x0f542e36, 0x0465d502, 0x0d0570b8, 0x05ff5f42, 0x135d84e2, 0x0933ca31, 0x03d9f796, 0x108e5a34, 0x3170c5}}, + {{0x163288b5, 0x1623ad77, 0x066f86f1, 0x1eead2b3, 0x1773d006, 0x0849ff5c, 0x1f88dd45, 0x025f874f, 0xb20836}}}, + /* 11*16^15*G: */ + {{{0x1c7548e9, 0x0cd91d2e, 0x04b5531e, 0x1b500e11, 0x03fe5d8d, 0x00b4a783, 0x180a76d2, 0x152145a7, 0x92fab0}}, + {{0x0917758f, 0x03896682, 0x0b421223, 0x01b8d1de, 0x079ffc8a, 0x18a70613, 0x1af3d0c5, 0x0d019648, 0x55e7b4}}}, + /* 13*16^15*G: */ + {{{0x1498f7f8, 0x06c0285c, 0x104588b8, 0x1ecfa64c, 0x08712c4d, 0x108d8c96, 0x145e742f, 0x17c3006a, 0x91b065}}, + {{0x1f23195b, 0x03a06cf1, 0x0258e78f, 0x18f684af, 0x1e264df2, 0x19a4800b, 0x1883fe7f, 0x0eff6ce2, 0x35b6f}}}, + /* 15*16^15*G: */ + {{{0x0060e322, 0x0ee5f712, 0x113452d4, 0x1b8e6f53, 0x0b9923ec, 0x034ba44d, 0x0cea70e4, 0x09995939, 0x8e4a1f}}, + {{0x104619d7, 0x110c1e6c, 0x13eff813, 0x01531b2a, 0x07bc4fb0, 0x0f692037, 0x1dd4bec1, 0x0bd6651a, 0x4936b7}}} + }, + { + /* 1*16^16*G: */ + {{{0x0e14db63, 0x073ae5a4, 0x1947dfa4, 0x1277555a, 0x025de294, 0x0c971937, 0x0a961249, 0x17850235, 0xfa822}}, + {{0x1f462ee7, 0x008922a2, 0x1fa0bd79, 0x034ca0a1, 0x1188b34b, 0x0a5e59ef, 0x0035bd2b, 0x1d1ebb75, 0xbff44a}}}, + /* 3*16^16*G: */ + {{{0x1db3cdec, 0x096229fb, 0x0a3afd5d, 0x1e742564, 0x04bc8dbe, 0x122f3df5, 0x1d739659, 0x0c9ff225, 0x85b2c0}}, + {{0x0a03f81f, 0x1a684102, 0x133e3823, 0x101669cc, 0x06d00dc9, 0x1d1697e6, 0x14d98f1f, 0x11e73a22, 0xf64b27}}}, + /* 5*16^16*G: */ + {{{0x0607b030, 0x0452d724, 0x01359cca, 0x15fec7cb, 0x0f29c24d, 0x1dd6760b, 0x119de147, 0x0ed88042, 0x110b03}}, + {{0x13617c3a, 0x01d50895, 0x0a61d27d, 0x1c2aadf6, 0x1c70c87b, 0x1c4fc230, 0x19cd31ba, 0x10a631dc, 0x84432b}}}, + /* 7*16^16*G: */ + {{{0x15a76f08, 0x076ec0e3, 0x0efb5395, 0x0be4a717, 0x0aaf8329, 0x1092158e, 0x075c53db, 0x0893ec8e, 0x18784e}}, + {{0x0b824993, 0x19cb02eb, 0x02894c82, 0x1ae94f4c, 0x1e671fc9, 0x147ed638, 0x0b9c5dde, 0x0fe943c3, 0x8d76ed}}}, + /* 9*16^16*G: */ + {{{0x1a6fad81, 0x14719e4f, 0x032c0fb3, 0x06cae918, 0x0037d9c3, 0x16ebb81d, 0x1ae6bbd5, 0x1c0fa0bc, 0x58a2f9}}, + {{0x1b109594, 0x00030af1, 0x0c02e095, 0x1765a65a, 0x1a6bd798, 0x017c38bf, 0x038306da, 0x18b58aac, 0x6ab64}}}, + /* 11*16^16*G: */ + {{{0x1eb52583, 0x191788fc, 0x03304ebe, 0x15339d82, 0x1676fea8, 0x16dd93c7, 0x0e8903b9, 0x1b99cfd7, 0x1ef020}}, + {{0x1a3f17ae, 0x0d93c0cb, 0x04b532d5, 0x0601f2e0, 0x095306ac, 0x1607a5cb, 0x12c025fd, 0x164b4f42, 0x594476}}}, + /* 13*16^16*G: */ + {{{0x10a1958f, 0x0e11f60f, 0x0d5990ed, 0x136a48df, 0x1a32c4f3, 0x0a267d5f, 0x084e5774, 0x0c783ad4, 0x4e4a81}}, + {{0x08636f8a, 0x01d9fa8a, 0x110f59a9, 0x0810bf65, 0x06fa8400, 0x051f714e, 0x03440cfd, 0x0b6f3d19, 0x2574a4}}}, + /* 15*16^16*G: */ + {{{0x04935db5, 0x013ad423, 0x1af6c3ba, 0x0f304c38, 0x0519e281, 0x1f076aca, 0x04138cc9, 0x02d5bac2, 0xf6966a}}, + {{0x1d166838, 0x11a41b60, 0x006fc04e, 0x08a74688, 0x0755e2d7, 0x172b961e, 0x16cb0697, 0x00f52063, 0xba0de3}}} + }, + { + /* 1*16^17*G: */ + {{{0x176a6987, 0x07a0982d, 0x1690ffda, 0x10356887, 0x01b3f2b4, 0x14c46bf7, 0x0551f771, 0x1af53313, 0x54bc18}}, + {{0x1b9aae49, 0x122be682, 0x1cec467f, 0x171da976, 0x1e2fd52e, 0x1c28dd39, 0x0bcdce46, 0x02423cdd, 0x4b2c8c}}}, + /* 3*16^17*G: */ + {{{0x1d1fd820, 0x05fa3faf, 0x1d9d400e, 0x0f0a8c90, 0x1271b788, 0x08113158, 0x14aaa18d, 0x1ed01838, 0xbafbbc}}, + {{0x1bf074f0, 0x176d6a90, 0x07f2b5ba, 0x18694246, 0x1c0fde81, 0x1fad644d, 0x1604b39e, 0x0f93b69b, 0x148799}}}, + /* 5*16^17*G: */ + {{{0x14299b7e, 0x08b84094, 0x01b8343a, 0x0f3e5a13, 0x020ec24e, 0x1dfe3ae1, 0x07f8a8f0, 0x1ee20671, 0x9b1938}}, + {{0x047b84de, 0x0bd942ba, 0x1ae08cb1, 0x1bd0a3f0, 0x03ec90ac, 0x14c70e55, 0x0a0cc503, 0x0dde2e20, 0xfb12aa}}}, + /* 7*16^17*G: */ + {{{0x110cc4c4, 0x0a083a06, 0x094f683f, 0x1a6b4589, 0x01b2cb71, 0x0fee033b, 0x1641f0e0, 0x10b9802e, 0xa67719}}, + {{0x1c976570, 0x1079d91b, 0x1fcc2530, 0x08aee74d, 0x19c3dbc7, 0x0b300f2e, 0x1663ca6f, 0x10beea1b, 0x855061}}}, + /* 9*16^17*G: */ + {{{0x14242a28, 0x0084016a, 0x0f29dc55, 0x1796424a, 0x14eca455, 0x17bc25bb, 0x1f0427a2, 0x0a6d61d5, 0x88b7ed}}, + {{0x194ed8ce, 0x1cb40f63, 0x00f8d1fe, 0x0cd4391f, 0x1bd934e3, 0x1cee9ac3, 0x11791fef, 0x040c48a6, 0x22b053}}}, + /* 11*16^17*G: */ + {{{0x1bc1a94c, 0x0b0a2764, 0x1c76be00, 0x0e3a567c, 0x08757516, 0x1958112f, 0x0f4814b5, 0x002550d6, 0x37114}}, + {{0x0fc2073c, 0x00605b67, 0x110920e3, 0x03186c55, 0x05335c85, 0x10d2a568, 0x0e43be30, 0x07aa3bae, 0x4d1d69}}}, + /* 13*16^17*G: */ + {{{0x077f88ba, 0x1de8f04c, 0x06fb4dbb, 0x100ef3dd, 0x02cc3509, 0x11974275, 0x04f8d2d6, 0x09913085, 0xcc9821}}, + {{0x07885278, 0x123177e4, 0x0d531382, 0x0c1cfdde, 0x163abeff, 0x053233be, 0x1ea44531, 0x1d1ca4b5, 0x4ebb4}}}, + /* 15*16^17*G: */ + {{{0x1d70187c, 0x0b98ca6f, 0x19031fc5, 0x1590c536, 0x15bf8751, 0x12f01487, 0x043e6053, 0x00534854, 0xad3ae}}, + {{0x1fc775a7, 0x0ffe7a59, 0x18a83d9f, 0x09f6102c, 0x1b33dd03, 0x0af82fd5, 0x1b8de171, 0x1a8eb108, 0x2af040}}} + }, + { + /* 1*16^18*G: */ + {{{0x10aae231, 0x0557d68b, 0x1e5adf18, 0x0970a4f3, 0x1756f519, 0x0411c933, 0x0fca17c9, 0x0d32ec3c, 0x1d35c9}}, + {{0x0cd6ac71, 0x033831d6, 0x0699bc56, 0x0b1548e5, 0x1f810edf, 0x055b1175, 0x008c7598, 0x16c5bec1, 0xc7226c}}}, + /* 3*16^18*G: */ + {{{0x0cfa3fac, 0x1069ff0c, 0x0ae064f3, 0x1b0d3f86, 0x1803023a, 0x1da2eb06, 0x0d338b3a, 0x08f4da44, 0xdf3d40}}, + {{0x0fc7d419, 0x03136c9c, 0x020a5d7d, 0x0c79c92d, 0x19dbfafd, 0x10f94e07, 0x036c92a8, 0x0a453fa8, 0x48fa6f}}}, + /* 5*16^18*G: */ + {{{0x1f1322d4, 0x16c92d70, 0x13372eeb, 0x14d28095, 0x1f822cb0, 0x16265188, 0x0513a879, 0x0d563f2c, 0xdbb2af}}, + {{0x0a8c5311, 0x12495a7a, 0x1f8e97ea, 0x1f92f0f6, 0x13f9d9a9, 0x068f6b21, 0x186a86d8, 0x1725e26a, 0xebae75}}}, + /* 7*16^18*G: */ + {{{0x01138f7b, 0x034d19e5, 0x1cba3cbc, 0x03927c5b, 0x15f0bc4c, 0x05133fcd, 0x1f532bea, 0x0b2fe4c3, 0x1dba7b}}, + {{0x039bf268, 0x0416c63d, 0x008cb037, 0x0dcd6f33, 0x007f5813, 0x08035dc0, 0x1f18eb86, 0x07cbbcfd, 0x6aaf7d}}}, + /* 9*16^18*G: */ + {{{0x179a70af, 0x0d43bb80, 0x1937ca23, 0x1a853536, 0x105c6ec9, 0x1416afa9, 0x0674c6ef, 0x0884c4d2, 0x348a2e}}, + {{0x07b66e82, 0x142430a4, 0x184f96b2, 0x0f858b6f, 0x10105b2a, 0x1de70011, 0x1a0231d1, 0x0f3eab47, 0xa1b9fa}}}, + /* 11*16^18*G: */ + {{{0x04d3a201, 0x1a3b6bb6, 0x06e7bbf1, 0x124d49fb, 0x0df5f36e, 0x07dfc98d, 0x1872a1a9, 0x0a333393, 0x3a4ec8}}, + {{0x08635f89, 0x0c2cb7bb, 0x0f3556f7, 0x063cb5ee, 0x14a8b27d, 0x1e08d23b, 0x0b79a780, 0x1f05ec4c, 0xc99a2e}}}, + /* 13*16^18*G: */ + {{{0x1c978567, 0x17d7397e, 0x1707e607, 0x1b4d1081, 0x1f60be15, 0x1aeb17f8, 0x115e13a4, 0x1b10669a, 0xb1ba52}}, + {{0x162dc291, 0x1fd24151, 0x1f35029d, 0x08d96175, 0x1b78fd9a, 0x1e7b89ed, 0x0e9df17d, 0x18f50d28, 0xa46bae}}}, + /* 15*16^18*G: */ + {{{0x12350da1, 0x11477528, 0x1d7c10f4, 0x0298ef82, 0x12c2f194, 0x1bdcb4b0, 0x0bf49c62, 0x07b1de55, 0xae6eb}}, + {{0x10a14bc3, 0x19f04f9b, 0x10f692f1, 0x08d1e1da, 0x189b566d, 0x1a7bfe20, 0x12b8b740, 0x13f6c00d, 0x99cdee}}} + }, + { + /* 1*16^19*G: */ + {{{0x150e4f5f, 0x0b957543, 0x19f83995, 0x0b95354a, 0x0f29acbf, 0x187bd501, 0x0bbce23f, 0x0b30896b, 0x55d9a9}}, + {{0x1ca97db0, 0x02c75bb5, 0x0b46c572, 0x10218c67, 0x0ec524c9, 0x0ba7de64, 0x080dd9b5, 0x1354bb5a, 0x69cb7f}}}, + /* 3*16^19*G: */ + {{{0x1eb142e9, 0x0354c43f, 0x01ff3ef0, 0x0dd60c8c, 0x0d480c17, 0x0341c7d7, 0x1845e536, 0x1d7c8de7, 0x4b0043}}, + {{0x02c68552, 0x0596296b, 0x04962201, 0x06521e74, 0x02d870f2, 0x04231b11, 0x106b6c5e, 0x047461b5, 0x173ccf}}}, + /* 5*16^19*G: */ + {{{0x17f1aa96, 0x16ea5738, 0x1fd9207d, 0x0f4bee69, 0x063c513d, 0x06e5db9a, 0x1f08c9ca, 0x0f3255ad, 0x79ead2}}, + {{0x0b0a3fb7, 0x05d38e72, 0x0ce556a0, 0x09ae2223, 0x16542de8, 0x01c9ab12, 0x0afc69b9, 0x19ff755b, 0xa95de9}}}, + /* 7*16^19*G: */ + {{{0x193a9ae6, 0x002e5397, 0x1dfe2b72, 0x01540b38, 0x1743f8ee, 0x0f1b18d6, 0x073ad49e, 0x0a1e49b4, 0x318e00}}, + {{0x1c447d79, 0x025ab4a6, 0x14ea3b86, 0x06dfb75d, 0x04bd0945, 0x1e528f28, 0x0a67d345, 0x022339d2, 0x2792ee}}}, + /* 9*16^19*G: */ + {{{0x1d30585a, 0x1bca2da6, 0x14052544, 0x1f143546, 0x0a4b495f, 0x197a4860, 0x10eee200, 0x0e3a5e3c, 0x6bbc54}}, + {{0x148b05f3, 0x17cbf779, 0x1e7ab65a, 0x00850205, 0x026be09f, 0x1158af91, 0x07c12a7b, 0x136182a5, 0x467b18}}}, + /* 11*16^19*G: */ + {{{0x00136275, 0x1127c046, 0x01dd4d49, 0x0f8002e7, 0x00d78a64, 0x0d487bbb, 0x144626d4, 0x18c2183f, 0x940148}}, + {{0x1997aa47, 0x0b1d088a, 0x13869097, 0x1675cac0, 0x1d6695d4, 0x06255a82, 0x13ddea89, 0x0be26cf4, 0x6967f9}}}, + /* 13*16^19*G: */ + {{{0x1f0fe850, 0x1d09ee9c, 0x0469ef70, 0x1a4617ca, 0x1f98e864, 0x164946d2, 0x127246d5, 0x124c0736, 0xc41833}}, + {{0x1d38666d, 0x1ac7a235, 0x0682bc04, 0x14fd93c0, 0x1d558065, 0x0aea1357, 0x1debae02, 0x19391a81, 0x3537fe}}}, + /* 15*16^19*G: */ + {{{0x14937fbe, 0x1f2209bb, 0x146e9bb3, 0x009bbbe0, 0x0f546c0b, 0x0000d7cb, 0x15c38305, 0x1ec4f8cf, 0x2baba3}}, + {{0x173a1df4, 0x1c872aba, 0x0b204424, 0x1b896321, 0x0abc9ec2, 0x1866c927, 0x0e235e0e, 0x0cb64411, 0x77e5c7}}} + }, + { + /* 1*16^20*G: */ + {{{0x0351964c, 0x069e96f2, 0x1504b075, 0x12486ede, 0x15c08346, 0x1e50c2ba, 0x11feb96a, 0x0b37c518, 0x6e29f9}}, + {{0x163fd88f, 0x0c4125ea, 0x02fed8c4, 0x0818a4f4, 0x0246def6, 0x163660c2, 0x0bd9414b, 0x13ea01e6, 0x34565d}}}, + /* 3*16^20*G: */ + {{{0x0c0e49cc, 0x1ca8081c, 0x1150034f, 0x065b50b7, 0x140ed412, 0x046f65db, 0x1dbb760a, 0x152f12e1, 0xd691d4}}, + {{0x100f4152, 0x085da60e, 0x1410fcb7, 0x17c3a055, 0x00c52ac5, 0x1edabb1f, 0x0e5fdfee, 0x10e96f1e, 0x7a79e7}}}, + /* 5*16^20*G: */ + {{{0x0b9b930a, 0x0c3b5cf9, 0x0c3d63cf, 0x026a548a, 0x1bc49deb, 0x1befbd3d, 0x1f177b96, 0x08d45c1a, 0x2a5d68}}, + {{0x1b2caeca, 0x17f9a2f9, 0x09c5a161, 0x16e686bc, 0x0ab58ea5, 0x181c81e2, 0x1db79733, 0x012d0ec8, 0xdc3d7c}}}, + /* 7*16^20*G: */ + {{{0x016959ef, 0x13ee5e94, 0x076d66be, 0x13a0ace8, 0x15df8767, 0x18a09713, 0x1498bc10, 0x0d471376, 0x876449}}, + {{0x00cd5010, 0x10188e5f, 0x1e78fc59, 0x0d5a82e5, 0x1961f285, 0x0093cb76, 0x1ff6782d, 0x1ac3a005, 0x599b69}}}, + /* 9*16^20*G: */ + {{{0x1aef0f84, 0x1ca04e71, 0x071d6e58, 0x16a0d50e, 0x1b8cab0b, 0x1fd60bd6, 0x06c4cf78, 0x1790248e, 0x94d393}}, + {{0x178ba7c1, 0x0d730dc9, 0x0b3c4aa1, 0x1e804ca1, 0x19a07dd3, 0x1e1c3591, 0x0fc87872, 0x169d696c, 0x5a826a}}}, + /* 11*16^20*G: */ + {{{0x0ffed1b7, 0x0a2abc27, 0x12a8ed3b, 0x17a24cac, 0x0bd2ee2d, 0x04b8169a, 0x18b745d4, 0x141113c9, 0x4a72b5}}, + {{0x1601dc5f, 0x0f94fec4, 0x1366116d, 0x0c971d8e, 0x0ea9685e, 0x1fe023e4, 0x038b230c, 0x1d4943a4, 0x3531e6}}}, + /* 13*16^20*G: */ + {{{0x10467317, 0x1021f92e, 0x16461a80, 0x03b883b1, 0x07900914, 0x13797d6f, 0x18569e19, 0x1f8b46e3, 0xd7f01c}}, + {{0x0f7d014e, 0x05cabeae, 0x1fef6257, 0x002e86d2, 0x1ef5728a, 0x10a0360a, 0x109bb1cd, 0x1b30ee4d, 0x888dbb}}}, + /* 15*16^20*G: */ + {{{0x1dea02c1, 0x1ebac853, 0x1d021f0e, 0x17736f8e, 0x11206e4f, 0x1fcec8f1, 0x1c6efa02, 0x173eef86, 0x7e50a0}}, + {{0x0d45c201, 0x1e4a36ff, 0x0386ca0c, 0x07269e2b, 0x19517742, 0x178eedc5, 0x0a7185b1, 0x0789c1fc, 0xc3405d}}} + }, + { + /* 1*16^21*G: */ + {{{0x0cb71280, 0x053ea088, 0x1158c44a, 0x0384b350, 0x1458ec14, 0x17783cb7, 0x1b67003c, 0x13d657fd, 0xff046a}}, + {{0x1ec33919, 0x161938fa, 0x0a121e9f, 0x16dcdd7a, 0x0fcc9012, 0x16edeea6, 0x085c2807, 0x159812a7, 0x432f55}}}, + /* 3*16^21*G: */ + {{{0x13ca3ce3, 0x193c1551, 0x1a9df897, 0x1630cb56, 0x0231fef2, 0x1e0fa989, 0x134c6a56, 0x0ba29a7b, 0xf717c4}}, + {{0x10ed88e9, 0x04a666da, 0x05db7c1a, 0x07c57bb8, 0x1ee55af5, 0x0a768556, 0x04b72a6d, 0x0ed1932a, 0x422c40}}}, + /* 5*16^21*G: */ + {{{0x1b28cd88, 0x1b42186a, 0x0a6f66b0, 0x1c12ea05, 0x1b32c738, 0x1ab13fc8, 0x0c830bfa, 0x169e66e1, 0x60e269}}, + {{0x0be2066c, 0x14dd4521, 0x1211ac38, 0x0ac2718d, 0x0df76024, 0x08c44b94, 0x02a58248, 0x0b4caf3e, 0xfe0017}}}, + /* 7*16^21*G: */ + {{{0x061cc594, 0x09d8c994, 0x1414dac5, 0x17ba2e09, 0x06855964, 0x1d02fe5a, 0x05242a96, 0x143cce73, 0x799297}}, + {{0x0f8d309e, 0x14888490, 0x0b1ba427, 0x150d5c17, 0x1e50127d, 0x088c3c4f, 0x06c3841a, 0x119aa479, 0x132ff1}}}, + /* 9*16^21*G: */ + {{{0x172d0aba, 0x04623d12, 0x1f86c5b7, 0x03215b8e, 0x1241dd8d, 0x0775aa80, 0x01c1e7b8, 0x09dfc850, 0x2d9be9}}, + {{0x11fa0876, 0x07b98fd9, 0x0dc439be, 0x038cf311, 0x1d91bbad, 0x1c9a5b0c, 0x0288a57b, 0x16bd3d13, 0xa9708d}}}, + /* 11*16^21*G: */ + {{{0x155e8732, 0x0603da41, 0x1b478c78, 0x0c5dbca0, 0x0c243cfa, 0x03298a49, 0x0859832f, 0x13d91048, 0x212703}}, + {{0x00cacc07, 0x0c91afa3, 0x15ef5a35, 0x07e7e775, 0x10a5cd69, 0x1cedddbf, 0x16a80652, 0x0de475c6, 0x85219c}}}, + /* 13*16^21*G: */ + {{{0x12083347, 0x0489a067, 0x0694c898, 0x15c7ccee, 0x0b42b9e1, 0x07ad5d01, 0x03ae5eb4, 0x09657b1c, 0xfab5b5}}, + {{0x1d38fd2f, 0x0664e6c1, 0x09a6bea7, 0x1c6f4c2d, 0x03eafc05, 0x15791305, 0x0540f21e, 0x02c30da8, 0x5758d1}}}, + /* 15*16^21*G: */ + {{{0x1f572554, 0x1b3930a7, 0x1d36adcf, 0x085c8e31, 0x0a56ff38, 0x0b3b85bf, 0x1f295e42, 0x0ae4f2e3, 0x685d27}}, + {{0x00979e03, 0x18d7b685, 0x1d33292d, 0x15545581, 0x0377cc58, 0x0e4020f0, 0x17f01b8e, 0x18441568, 0xa82f89}}} + }, + { + /* 1*16^22*G: */ + {{{0x05852e50, 0x1e859266, 0x15c33171, 0x18fcc79e, 0x07eff8b2, 0x1511a4f7, 0x016307e6, 0x1bffd576, 0xe486c7}}, + {{0x0ecf107d, 0x15d1e56d, 0x04baf619, 0x08c7ac67, 0x1e05a694, 0x052e4fa8, 0x04ba7ba2, 0x1daac0d4, 0x51fd75}}}, + /* 3*16^22*G: */ + {{{0x1c881907, 0x1355322a, 0x002c76b1, 0x190ce6b6, 0x00415142, 0x02e63357, 0x0df25904, 0x1771c5ff, 0x4acf44}}, + {{0x163cdafc, 0x0935a2b7, 0x1612c94a, 0x0a565ef9, 0x05457993, 0x142d6885, 0x01ecd510, 0x1fc1ffab, 0xad99a8}}}, + /* 5*16^22*G: */ + {{{0x1439383f, 0x15d7034b, 0x0068aaa0, 0x1f4ac56c, 0x14eec34f, 0x11496411, 0x192775ea, 0x10683114, 0x4ddf22}}, + {{0x03d52337, 0x197d40c1, 0x07e09a58, 0x0ba08a26, 0x00c6b3dd, 0x174be9c6, 0x00f5d2ae, 0x0f61b231, 0xe71c62}}}, + /* 7*16^22*G: */ + {{{0x1822b4f4, 0x16e440aa, 0x1977e3c9, 0x0a75f9f0, 0x1f39ba53, 0x14f03cbd, 0x1e784cd3, 0x0f226f30, 0x58b065}}, + {{0x0c60fbca, 0x103d4108, 0x13949659, 0x0940edf8, 0x0836c1ca, 0x12af8131, 0x10dc09f2, 0x14828b45, 0x55a98a}}}, + /* 9*16^22*G: */ + {{{0x14fe39b0, 0x195e8861, 0x0d37b452, 0x02e79ae9, 0x01f358a3, 0x020e119c, 0x14a5d8e9, 0x0b14c966, 0xa345e0}}, + {{0x0baf79dc, 0x184a405d, 0x0da77d4d, 0x18d4eb56, 0x1d949ce8, 0x02ad947c, 0x1c3e47c2, 0x14dab954, 0x7c6dd5}}}, + /* 11*16^22*G: */ + {{{0x126695fb, 0x1df03dcc, 0x0eb7b84f, 0x01773fc8, 0x0ccb6afd, 0x05c3a36b, 0x0b20806b, 0x10603214, 0x3a10bf}}, + {{0x04eb7e47, 0x0ae39595, 0x1514a21d, 0x1fd4d887, 0x065c5f28, 0x1c243445, 0x1c55d880, 0x167d8344, 0xb5d585}}}, + /* 13*16^22*G: */ + {{{0x1d2c8614, 0x00d474b3, 0x16116589, 0x012c14c0, 0x12876a7b, 0x1ad61848, 0x10cf2973, 0x1f592020, 0x12fbdd}}, + {{0x18b0b174, 0x03bde0ea, 0x067d257c, 0x04b04738, 0x0cfb54d4, 0x08a14669, 0x01a0cff6, 0x1a5204f0, 0xa5ff20}}}, + /* 15*16^22*G: */ + {{{0x0d9aeeaf, 0x1fbb2181, 0x16bf2194, 0x00f29940, 0x19a3005d, 0x11d0fd7c, 0x01ddee2b, 0x0b34572f, 0x8bece8}}, + {{0x05f9eb5e, 0x0d06d1e4, 0x02603dd5, 0x04071edf, 0x1c368bb2, 0x0885877f, 0x07f3eee2, 0x1898a0ca, 0x35f933}}} + }, + { + /* 1*16^23*G: */ + {{{0x0b519178, 0x05b5c761, 0x0f47f161, 0x17333148, 0x0ee0ab63, 0x067c5af1, 0x10c33f82, 0x0976bca0, 0xf41d7f}}, + {{0x0a6a3551, 0x1d0b32ee, 0x06787e69, 0x135986d2, 0x02347ab4, 0x16f1fd54, 0x035bc411, 0x17d7b35f, 0xe6a669}}}, + /* 3*16^23*G: */ + {{{0x1e3501d9, 0x138989f0, 0x187f22c6, 0x1059c376, 0x13e611be, 0x0b48eb16, 0x19fccccb, 0x0fdac5a9, 0xd65f82}}, + {{0x0b55759e, 0x1ca23637, 0x1cc2f86a, 0x02755aba, 0x187fc61c, 0x1e528b35, 0x03f94ded, 0x1f9e1352, 0xf24b60}}}, + /* 5*16^23*G: */ + {{{0x0f2ed84e, 0x1b17f120, 0x18ba84b2, 0x129be6bf, 0x0c0ade79, 0x045abc16, 0x10e17b9b, 0x16dbd60b, 0x55a9b5}}, + {{0x146495a3, 0x1cee2a82, 0x08363c15, 0x1f69ae25, 0x1f43ae8f, 0x068c876b, 0x06aca45d, 0x12d593e3, 0xc4f221}}}, + /* 7*16^23*G: */ + {{{0x075495a2, 0x1e967c38, 0x0f002ca6, 0x1c3d6c91, 0x08bc49fd, 0x0b05312a, 0x07687dfb, 0x0db8fb6e, 0x79de57}}, + {{0x0aec6fb8, 0x01646355, 0x04e9d1a0, 0x09ea12c9, 0x079c6831, 0x16d723ee, 0x0809e179, 0x01cd630d, 0x3b2d3d}}}, + /* 9*16^23*G: */ + {{{0x02d1e7bb, 0x17495664, 0x0465933b, 0x07ff206a, 0x1e55524c, 0x19b4acab, 0x12db8992, 0x0642c480, 0x8fe04e}}, + {{0x1a62e84f, 0x13acd686, 0x011aa336, 0x02c8c8de, 0x1b34e5b9, 0x0752bd46, 0x163f975b, 0x0a045ec6, 0x3987db}}}, + /* 11*16^23*G: */ + {{{0x09f7c360, 0x00d25763, 0x00217084, 0x19aaefc9, 0x024e24ef, 0x0531b469, 0x03c542a5, 0x012afdbf, 0x3af499}}, + {{0x087d7a7b, 0x1cee1553, 0x18225734, 0x0a9bac4e, 0x13c33485, 0x03241739, 0x04754c7e, 0x061a763b, 0xd17060}}}, + /* 13*16^23*G: */ + {{{0x170373be, 0x0d291d73, 0x18f4ed4e, 0x1a0c4424, 0x07c4e213, 0x0179ff11, 0x01db0696, 0x0b8c4790, 0x31a7e0}}, + {{0x090950a8, 0x16bc3c87, 0x08950c23, 0x105732a3, 0x1db1e8ce, 0x05571a11, 0x199c086c, 0x1e7f1a3b, 0xc23d2e}}}, + /* 15*16^23*G: */ + {{{0x0b923b45, 0x0130876e, 0x0f892f6d, 0x153f7fe2, 0x18458a33, 0x09a316ec, 0x08fb4554, 0x09026ada, 0x740a66}}, + {{0x11ecaa5f, 0x0609f1c2, 0x121202ea, 0x0f32720f, 0x006cfa89, 0x03c453ab, 0x08fcbd39, 0x1184b9aa, 0x7f6d04}}} + }, + { + /* 1*16^24*G: */ + {{{0x1512218e, 0x025549cb, 0x1280506a, 0x0a4360e9, 0x0e902e9a, 0x059d0c51, 0x1e995e20, 0x0cc254ce, 0x4a5b50}}, + {{0x0c4f3840, 0x1f56d3d2, 0x189b6742, 0x1b62a833, 0x07d40626, 0x027df0b1, 0x07c71098, 0x039d5811, 0xeb1346}}}, + /* 3*16^24*G: */ + {{{0x118473fd, 0x177a0712, 0x05cce454, 0x1204d78d, 0x0a9e3bbb, 0x155ccb94, 0x0e8214a4, 0x06466631, 0x106406}}, + {{0x185cf805, 0x1d30b173, 0x08740e6b, 0x1c321a18, 0x1883ccfb, 0x014f32c2, 0x0b63239e, 0x10477174, 0x9c6832}}}, + /* 5*16^24*G: */ + {{{0x053f30f3, 0x0b3f7643, 0x088e374d, 0x047da5db, 0x03f212b4, 0x0086aa04, 0x1efd7b69, 0x11fe0be4, 0x38c8ad}}, + {{0x0be9217b, 0x03073a4f, 0x1677cde8, 0x07f53052, 0x1641f658, 0x0b2a6ede, 0x045bce42, 0x0f0edb96, 0x83c261}}}, + /* 7*16^24*G: */ + {{{0x16ef1584, 0x01f3488d, 0x04832fd5, 0x1345471f, 0x1184277a, 0x1df1fe9a, 0x0c256163, 0x179d0c17, 0x6fcb8c}}, + {{0x1d3110f2, 0x1e4fbe10, 0x0290c970, 0x05edad25, 0x0459d599, 0x0411d618, 0x15db5530, 0x07b16e43, 0xa8f1a8}}}, + /* 9*16^24*G: */ + {{{0x062255ef, 0x07a89a02, 0x1901e33a, 0x0e3a68ce, 0x1b0ee50d, 0x0e486f22, 0x0af5cd45, 0x1727eedc, 0x7811d0}}, + {{0x1be3252e, 0x0c5f7cd8, 0x150dda29, 0x1da0a275, 0x05132f51, 0x174a00dc, 0x11e95300, 0x06e176b5, 0x99bb76}}}, + /* 11*16^24*G: */ + {{{0x153d2ea7, 0x1f088789, 0x1ea19424, 0x1a104747, 0x16f2a9ee, 0x194eafc0, 0x033831ed, 0x1289516a, 0xc3583d}}, + {{0x0b667bbd, 0x18c1f4f0, 0x17c710ca, 0x124b4ca2, 0x1cccdd6c, 0x113f7c4f, 0x043d6591, 0x1812723d, 0x53967a}}}, + /* 13*16^24*G: */ + {{{0x102e3099, 0x16ef8702, 0x01005963, 0x04274cc5, 0x0d00d53f, 0x180c5dbd, 0x1407ce83, 0x05079bdc, 0xd591cf}}, + {{0x055ac5af, 0x1de13b2a, 0x045bf58c, 0x05dff116, 0x1c5825cf, 0x19869a85, 0x1b913944, 0x19f88f1c, 0x87ebe5}}}, + /* 15*16^24*G: */ + {{{0x12a940a5, 0x1932b231, 0x0539ac4a, 0x06bd6b48, 0x1e8714a4, 0x00f0d27c, 0x17130049, 0x0c25e646, 0xa0aa0d}}, + {{0x0b950422, 0x1fc41534, 0x146fe4e4, 0x1239bb4f, 0x01f3e6c6, 0x067cd00c, 0x10a066cd, 0x174edeec, 0x22340e}}} + }, + { + /* 1*16^25*G: */ + {{{0x008e2df0, 0x1146c1b8, 0x0a397dd9, 0x0764ae86, 0x00f5032c, 0x14efc5df, 0x065404b0, 0x017bc557, 0x2eb391}}, + {{0x1274eaae, 0x08866276, 0x1d97d242, 0x01a241d9, 0x0999f954, 0x1e9a46d2, 0x0ce9df4d, 0x0466e8e9, 0x3f29c0}}}, + /* 3*16^25*G: */ + {{{0x082867f0, 0x1815c25b, 0x06428e6f, 0x084dc436, 0x100f0a21, 0x08b53c04, 0x1388aaaf, 0x111cc98f, 0xf6e9db}}, + {{0x0f1861ea, 0x1ad9d788, 0x1c2d88d1, 0x08374bf2, 0x0d5b1270, 0x1dbb7460, 0x0dd20764, 0x016f5a55, 0x53ca79}}}, + /* 5*16^25*G: */ + {{{0x120d6102, 0x16e821c7, 0x114e5026, 0x1aa6f146, 0x19a5ef06, 0x0adcdb0c, 0x1275e170, 0x070ec1c8, 0xfd1ddb}}, + {{0x0e003b7c, 0x1053248d, 0x144e60f6, 0x1c322422, 0x1b700163, 0x0f8fbc41, 0x0e2bb6a8, 0x0e720a0c, 0xcb54b8}}}, + /* 7*16^25*G: */ + {{{0x02c77cb7, 0x1fb9a0ee, 0x17056dbc, 0x1b281205, 0x0698fef6, 0x139f32f7, 0x00767f92, 0x1844b332, 0x61a273}}, + {{0x1ddb25ed, 0x0a308fc0, 0x0b87dd21, 0x0b5b34e1, 0x10cc9c5c, 0x10cfaf75, 0x0f4fd3a8, 0x0669a75a, 0x5bbacd}}}, + /* 9*16^25*G: */ + {{{0x177d8976, 0x0cc6ab71, 0x03ca4b6e, 0x0e7471c6, 0x104b55e1, 0x164c114e, 0x06d932c0, 0x0cbdeec0, 0xcd2e8e}}, + {{0x0867bc22, 0x0b4b7a0e, 0x10a30144, 0x1dbc1e6a, 0x0ff68f60, 0x074796a3, 0x0c7ff0c7, 0x06c46854, 0xf58ead}}}, + /* 11*16^25*G: */ + {{{0x0c67c998, 0x04d98361, 0x13c6e198, 0x160fd547, 0x04c259a9, 0x0f545218, 0x1bed0089, 0x13870447, 0x9bd61f}}, + {{0x08199514, 0x1a057ce1, 0x1092c630, 0x1b383d20, 0x050fa927, 0x104b4b4a, 0x1d71723c, 0x01322d8d, 0x77b204}}}, + /* 13*16^25*G: */ + {{{0x0aafa568, 0x122f0bdf, 0x07889d9a, 0x1af52ee0, 0x1a016b4c, 0x13d2088b, 0x1dd44ab8, 0x09ef2e0e, 0x7afaeb}}, + {{0x01c1f2df, 0x16a9d17c, 0x14e408cf, 0x1cd28653, 0x1365a972, 0x0a09a820, 0x09f62574, 0x03267f7a, 0xc6efe6}}}, + /* 15*16^25*G: */ + {{{0x0e59ddeb, 0x1f381f28, 0x07a62a2d, 0x1cc5395a, 0x10c3b483, 0x0a60a4b5, 0x0be41876, 0x044fc482, 0xd9a002}}, + {{0x0f0af5a4, 0x19c9ffc0, 0x17c63397, 0x05517956, 0x10581856, 0x07c521b3, 0x08b10f18, 0x1f276f40, 0x975eb2}}} + }, + { + /* 1*16^26*G: */ + {{{0x1ecca7e0, 0x19cd2f51, 0x10cccfb1, 0x05931ece, 0x19428a7d, 0x119a9126, 0x08303fbd, 0x078b8f25, 0x7ef2ee}}, + {{0x152ac094, 0x015916ea, 0x0f4f480c, 0x0428a1bf, 0x009db81b, 0x1fa8eaf3, 0x004693d9, 0x04e61598, 0xafb686}}}, + /* 3*16^26*G: */ + {{{0x033f0ffa, 0x179ac1ed, 0x001e905c, 0x09958c23, 0x1c641cae, 0x12bb64ec, 0x0b35d892, 0x04e2d10f, 0x370457}}, + {{0x00fa35ac, 0x1f69fe33, 0x02fcbf17, 0x147d6f55, 0x1ff4c57b, 0x1a5dc44a, 0x1d3e106e, 0x18c34e3c, 0x5c6408}}}, + /* 5*16^26*G: */ + {{{0x12603513, 0x037cc329, 0x1280254f, 0x0c9b8d02, 0x1b697f6c, 0x15216045, 0x0dc8b47a, 0x1ca8531b, 0xc2a979}}, + {{0x1c3505b9, 0x0baad961, 0x05451265, 0x0ccdbe90, 0x1ce7e8cc, 0x0040c9ad, 0x1721509e, 0x0943cdd6, 0xef9dd7}}}, + /* 7*16^26*G: */ + {{{0x19fdee3e, 0x1237fd8e, 0x0c0b8079, 0x1f2ee2d8, 0x1afb9681, 0x18ae6d8b, 0x07845cae, 0x0d563f8b, 0xc9f418}}, + {{0x0ced22e7, 0x0f33662e, 0x1637d3d4, 0x02a638f6, 0x1214344e, 0x18a15c41, 0x0d0437dc, 0x0fe79674, 0x9420a}}}, + /* 9*16^26*G: */ + {{{0x0814f217, 0x0659f33a, 0x15b3febc, 0x147ef70e, 0x1b6a4a9d, 0x00127c1d, 0x095ac228, 0x0b700900, 0x27dcf5}}, + {{0x0cf2ed4c, 0x064a5ac4, 0x07f0efc5, 0x1d1f5632, 0x02a380a4, 0x1d584a50, 0x17b82f22, 0x09ea91ab, 0xbe18f5}}}, + /* 11*16^26*G: */ + {{{0x1b9e310c, 0x0d1527ea, 0x133f529d, 0x19cb7370, 0x19187313, 0x125619ca, 0x092e7234, 0x00764add, 0x3b8b02}}, + {{0x0d19fc9b, 0x0a0b302d, 0x0cc160e6, 0x1f009705, 0x117a6a8f, 0x171bbe20, 0x056f585d, 0x09d6066c, 0x91117c}}}, + /* 13*16^26*G: */ + {{{0x07615b36, 0x18f0f15d, 0x1cf057e3, 0x1fe3d18f, 0x0c3372a4, 0x12037c8a, 0x00e84170, 0x118b7982, 0xa5e739}}, + {{0x09136d80, 0x0cc171ca, 0x0d84f013, 0x1f8326e1, 0x1f8c547f, 0x06f7950a, 0x1339190e, 0x11b92e9c, 0x1f3ff5}}}, + /* 15*16^26*G: */ + {{{0x0d3e10db, 0x1bd82197, 0x0e1c566e, 0x065c3591, 0x161fa477, 0x021ffa75, 0x0caf7b81, 0x06ab592a, 0xaad218}}, + {{0x0fa05fb3, 0x1a9ad5eb, 0x072e89d8, 0x064ee566, 0x18b4a720, 0x0f147eaf, 0x18ece9f7, 0x1dd75f05, 0x793b1e}}} + }, + { + /* 1*16^27*G: */ + {{{0x0c49e853, 0x180f8487, 0x1d781299, 0x16a6a532, 0x1a77aa9c, 0x12aa75af, 0x0bad5e00, 0x0c842c81, 0xe5141}}, + {{0x16405cb2, 0x1b71e89b, 0x127b8d8c, 0x10728321, 0x1030df56, 0x1a529d48, 0x11a49e3a, 0x1d4cb20a, 0xcf331c}}}, + /* 3*16^27*G: */ + {{{0x1dc6afad, 0x0511f8e0, 0x1e03d1b1, 0x07b2452b, 0x0c6771bd, 0x092fb260, 0x1c977a3b, 0x0cecb959, 0x977ba0}}, + {{0x1d7faa09, 0x0b166e28, 0x16868553, 0x0b42483b, 0x1d9992f7, 0x1d506840, 0x1e8a20cf, 0x0875db71, 0x1bc3bc}}}, + /* 5*16^27*G: */ + {{{0x1d81983b, 0x0fba2ebe, 0x03aade19, 0x041fa05f, 0x1facc102, 0x1b03b8ff, 0x0af930f2, 0x0c254247, 0x3bc328}}, + {{0x11a637b6, 0x0ccf9428, 0x0ee1236f, 0x0910b51f, 0x00a7f433, 0x182e5578, 0x0880942c, 0x0dbda191, 0xa6b582}}}, + /* 7*16^27*G: */ + {{{0x17c8537b, 0x0fbb60ff, 0x07e0185d, 0x19596e88, 0x16c21ca8, 0x17f0e57c, 0x12b146eb, 0x1d1d3d80, 0x67cba4}}, + {{0x185726da, 0x075a82b9, 0x100fdb87, 0x1e087da0, 0x1cc047bd, 0x030f97d8, 0x06128787, 0x1dbd4391, 0x5b65ed}}}, + /* 9*16^27*G: */ + {{{0x0b6a1226, 0x14114672, 0x15194e4d, 0x13d39156, 0x0f3922af, 0x1eb43234, 0x064c681c, 0x14daae93, 0xc5958e}}, + {{0x066961d4, 0x00803446, 0x08422e47, 0x0edb7d74, 0x1bd82968, 0x0cb8cea2, 0x175fb2f8, 0x105ee1ef, 0xa031a8}}}, + /* 11*16^27*G: */ + {{{0x13713a52, 0x06f1fc2d, 0x0f1505f9, 0x0eb718d0, 0x05fa025c, 0x0061e3a5, 0x129f07f3, 0x1f05c84b, 0x83f07b}}, + {{0x1fb0ffb6, 0x088939fc, 0x1ed174a8, 0x0b6ec1c3, 0x1d3cfcab, 0x0a648963, 0x0ee4125e, 0x02144b71, 0xf2ec4f}}}, + /* 13*16^27*G: */ + {{{0x01ba21b0, 0x16cd0489, 0x109954e6, 0x0bb1a401, 0x00076d85, 0x00343757, 0x0b539bda, 0x09f36b48, 0x938dba}}, + {{0x0d5b4325, 0x1a6ccaf2, 0x0ada5f0d, 0x0377dc7e, 0x0b90bcbf, 0x16dee89b, 0x1959ba6a, 0x15135eea, 0x48afc0}}}, + /* 15*16^27*G: */ + {{{0x1f2b24f1, 0x09f24d31, 0x19daf3ed, 0x1d8c9ebf, 0x09779cfa, 0x0d5679da, 0x079cea07, 0x16ed9406, 0x7efa89}}, + {{0x0f8e4b83, 0x12ee2ea5, 0x15291575, 0x15be758a, 0x0ab211db, 0x09117e0b, 0x1bfde33b, 0x1d8c3e95, 0xa99ff3}}} + }, + { + /* 1*16^28*G: */ + {{{0x02f2b734, 0x034cdfcf, 0x007499fc, 0x0776b6aa, 0x0445779c, 0x13c3788b, 0x066818d2, 0x0533dd99, 0x224a02}}, + {{0x11ec7fdf, 0x007ac2a4, 0x11ebf421, 0x0e096ce7, 0x17fff07b, 0x0456c38e, 0x0ad05268, 0x1a536da4, 0xfa41a8}}}, + /* 3*16^28*G: */ + {{{0x1d254033, 0x0f497a3a, 0x091c1eb2, 0x0d050185, 0x0f240783, 0x0fd3445b, 0x1167f36b, 0x1dc2a79d, 0xe63502}}, + {{0x08f05e3f, 0x1455444b, 0x1f3cd81f, 0x02b41897, 0x1ce482c9, 0x14078384, 0x1846b5d3, 0x0f63ec43, 0xa7c583}}}, + /* 5*16^28*G: */ + {{{0x01e08f33, 0x1cb04d7f, 0x060b328a, 0x1ac63b97, 0x000e2b1f, 0x02e299f8, 0x1a1c4aad, 0x184e5d72, 0x5648de}}, + {{0x0269f1c9, 0x1776cd62, 0x045e5449, 0x0577e5c0, 0x1a2693e7, 0x1ae326bb, 0x010fd1e3, 0x0e0e11ee, 0x95fddc}}}, + /* 7*16^28*G: */ + {{{0x1ab98c43, 0x1dc1005f, 0x0fa2a938, 0x14aeeafc, 0x08f03c5b, 0x17c765f6, 0x149a5454, 0x13e6701d, 0x1941c1}}, + {{0x02abe217, 0x1d1086d1, 0x17d58e63, 0x0c5a7b71, 0x18c53d8f, 0x0d95247d, 0x0adb8adb, 0x068b2bb6, 0x8e66b8}}}, + /* 9*16^28*G: */ + {{{0x02d8c2f4, 0x13386882, 0x07006279, 0x064373ef, 0x18a0bd73, 0x1def1b26, 0x0f59fe9c, 0x063a2169, 0xfc5864}}, + {{0x1cfd274a, 0x08c6447f, 0x10ce2d00, 0x05960bd7, 0x1b4ab29e, 0x013cf35e, 0x055928cf, 0x0a59d15b, 0x99fade}}}, + /* 11*16^28*G: */ + {{{0x11ff0f18, 0x1583bf8e, 0x12690b44, 0x0179ce0a, 0x0d6c207e, 0x1d67cd79, 0x077aa6fe, 0x14d6189e, 0xee993b}}, + {{0x050782ad, 0x009c3b65, 0x03cb2c60, 0x0b901bee, 0x1bcfeb43, 0x0eac6742, 0x0cb07db1, 0x1b28af1b, 0xd87fd4}}}, + /* 13*16^28*G: */ + {{{0x0fdde3fc, 0x03d3fbaa, 0x18a33279, 0x11113c0a, 0x131fbe5a, 0x0e20d297, 0x090a3683, 0x0f55d3fc, 0xba4951}}, + {{0x0fcb7d01, 0x1f7e9197, 0x0a4b2aa8, 0x1c3903c6, 0x1359adfd, 0x121bb009, 0x16542d3b, 0x1c39528a, 0xa88fb6}}}, + /* 15*16^28*G: */ + {{{0x1d14da68, 0x0449517b, 0x14805cde, 0x0983f09b, 0x012b54a6, 0x07c139bb, 0x06e9378b, 0x02e8455e, 0xd3398f}}, + {{0x15a90e3d, 0x183b18da, 0x10514e8f, 0x0f4f245a, 0x0b020afc, 0x0968f451, 0x1583adc9, 0x1a9a3fa7, 0xa34ad4}}} + }, + { + /* 1*16^29*G: */ + {{{0x1789b84d, 0x13032d6b, 0x010738ba, 0x1abdc9a2, 0x093fe167, 0x0888dab2, 0x0d3336d7, 0x028ae6e9, 0x4a89a6}}, + {{0x018e3ea8, 0x1cdbebf8, 0x1c46667b, 0x1c500c68, 0x077e6a72, 0x154bcff3, 0x1570230b, 0x10fda901, 0x45b04e}}}, + /* 3*16^29*G: */ + {{{0x02e14c34, 0x13b591ba, 0x0c9d64db, 0x18bd7c0e, 0x177c9834, 0x19873c09, 0x1e4a8aa6, 0x09150e1d, 0xcc9f96}}, + {{0x14be556b, 0x0490abd4, 0x031f8162, 0x122fe305, 0x089db299, 0x1319edf3, 0x05bd0c45, 0x0596bf19, 0x829bff}}}, + /* 5*16^29*G: */ + {{{0x15de4837, 0x1ef3642c, 0x1979d3a1, 0x050d905b, 0x18a758d4, 0x060e856c, 0x106bd3d6, 0x143f55a0, 0x5c618d}}, + {{0x034a7dee, 0x05c2c1db, 0x089e32b0, 0x06cc92c8, 0x19671ecd, 0x071c24fe, 0x067622e0, 0x02f79e74, 0x4c7191}}}, + /* 7*16^29*G: */ + {{{0x16635396, 0x0c49a132, 0x029b0309, 0x15c2b46d, 0x1c11ef2c, 0x116ef338, 0x1a8b9617, 0x0d522b40, 0xab8a88}}, + {{0x1fc92c23, 0x11c7d351, 0x14b5ab5f, 0x0c0b07ef, 0x0d5abb93, 0x1fc1245e, 0x0c6559a3, 0x0f8fb508, 0xe773cf}}}, + /* 9*16^29*G: */ + {{{0x01df49c3, 0x0121f2c4, 0x01a68d6b, 0x11210cda, 0x1604aa9e, 0x125c5b4a, 0x0e337b19, 0x0a284830, 0x62b7c8}}, + {{0x16341c21, 0x1f1b407f, 0x1f2d5426, 0x0a76c270, 0x122db8fb, 0x0b5746a4, 0x0cd56522, 0x042a55c0, 0xa71ed6}}}, + /* 11*16^29*G: */ + {{{0x044f47d0, 0x178a3717, 0x07c00bce, 0x13ebbd29, 0x1c9791b5, 0x0f8434ef, 0x0717e5d4, 0x17f48b91, 0x4897bd}}, + {{0x0e1320bf, 0x0f280d56, 0x1c046560, 0x1b400351, 0x1093f526, 0x1654a0bd, 0x0e30d3a3, 0x01ef5f82, 0xe77dc2}}}, + /* 13*16^29*G: */ + {{{0x11581bd3, 0x10de74db, 0x0641e1b9, 0x14631bec, 0x02f2ecbf, 0x103ded39, 0x15db1147, 0x16aac90c, 0xeb1cfc}}, + {{0x1cd98a09, 0x1e746cc2, 0x0f469916, 0x19e6338b, 0x16e3cb39, 0x002f5f26, 0x14814110, 0x0eae3f29, 0xfd47ce}}}, + /* 15*16^29*G: */ + {{{0x073a3111, 0x00915edb, 0x132063e4, 0x105c82f6, 0x176a018b, 0x05617392, 0x18270355, 0x177c91c3, 0xa1fd8b}}, + {{0x18c704ef, 0x043f3285, 0x15445a6e, 0x18928b7f, 0x116c0c7e, 0x1f03de04, 0x015a6f5d, 0x11469461, 0xad215d}}} + }, + { + /* 1*16^30*G: */ + {{{0x12bd05a0, 0x01c64253, 0x07f2034d, 0x0466fa16, 0x11f90ba8, 0x1ccaf9b6, 0x0173b70b, 0x06c74631, 0xe5e892}}, + {{0x01a69f5d, 0x09b6f15f, 0x14266bb2, 0x0732b739, 0x15c3eca7, 0x1580f3cd, 0x1f484c07, 0x1c9b4370, 0x77439d}}}, + /* 3*16^30*G: */ + {{{0x01467d6b, 0x184a9408, 0x0892d453, 0x1ae252a5, 0x0f1d8357, 0x0308b216, 0x13d74406, 0x1bf286b9, 0x5d2393}}, + {{0x11bc5458, 0x1e339e35, 0x011cea01, 0x0e0f4ea2, 0x0f46d72a, 0x0c2d96ad, 0x1df5eb2f, 0x1e4c7fa1, 0xe66e63}}}, + /* 5*16^30*G: */ + {{{0x1d159f7a, 0x058f49e4, 0x10b9643c, 0x127539e4, 0x1873fecf, 0x1d95e97f, 0x04fceb73, 0x14a75571, 0x453657}}, + {{0x0a02fb78, 0x0e115b84, 0x07769766, 0x0937a9d0, 0x1c7286f9, 0x18489d00, 0x171768bb, 0x1ff10047, 0xbfb5ae}}}, + /* 7*16^30*G: */ + {{{0x146cb42a, 0x0f6f6f9e, 0x08e424cc, 0x0a50a74e, 0x173e7bc0, 0x16f5509e, 0x11193452, 0x1960f609, 0x435b54}}, + {{0x1af72dd0, 0x1f126f6e, 0x0e5269ad, 0x1898f286, 0x0585d5ed, 0x12a660f0, 0x086927d2, 0x063c8e31, 0xd726c0}}}, + /* 9*16^30*G: */ + {{{0x1d2fc263, 0x0beca0d8, 0x19755eea, 0x1f027cb6, 0x1da0e89c, 0x023e2709, 0x15f867ef, 0x033c29db, 0x1805b8}}, + {{0x10870ec7, 0x132385a7, 0x147b2bc9, 0x1835f1ca, 0x131489c8, 0x0d5435e5, 0x05c56163, 0x05012870, 0x101f64}}}, + /* 11*16^30*G: */ + {{{0x0076d1df, 0x1158db86, 0x1fe86ce6, 0x1c410284, 0x15f45f41, 0x1d45153b, 0x053d0185, 0x086cda63, 0xc73aaf}}, + {{0x05ad6605, 0x13cea8b7, 0x024dc834, 0x16af4a3b, 0x0dcfef75, 0x00df1dde, 0x05bbe738, 0x0d3d99f2, 0x9201ec}}}, + /* 13*16^30*G: */ + {{{0x05a745c7, 0x1b41fbcc, 0x1fab01f4, 0x144e7182, 0x152c1bc8, 0x0db57b0e, 0x1b49dc62, 0x11efab86, 0xe3ddee}}, + {{0x178efcc2, 0x1cf84a03, 0x1409ec68, 0x1185e2f7, 0x1d8f47c2, 0x0dc3553d, 0x0e1c6f94, 0x1a723265, 0x487199}}}, + /* 15*16^30*G: */ + {{{0x0d4170b3, 0x06399f42, 0x0e8d61fd, 0x0882adf8, 0x0a1d5401, 0x1508c360, 0x0796bda2, 0x1b8406be, 0x45c78d}}, + {{0x111faa1d, 0x177d1f6a, 0x08331cc5, 0x008cc0c8, 0x13a512cb, 0x14e8a27d, 0x1032c386, 0x08c471ab, 0x11af99}}} + }, + { + /* 1*16^31*G: */ + {{{0x1ab5c2cf, 0x0abccc97, 0x0c213788, 0x05e1843f, 0x090a4531, 0x03a0827d, 0x1d41c79d, 0x0863c443, 0xe4107e}}, + {{0x0b955c2b, 0x014201f9, 0x1ec90434, 0x1125b9fe, 0x02b323c7, 0x03343a0e, 0x1268e523, 0x1cd9ee03, 0x1e5f11}}}, + /* 3*16^31*G: */ + {{{0x09b67b7e, 0x1dadb1e0, 0x070f5216, 0x16f65722, 0x01142766, 0x0b80ef5e, 0x1df6ab3e, 0x0cbdc2f3, 0x85df9a}}, + {{0x030a36e3, 0x059c34f4, 0x0f1ba962, 0x15293a3f, 0x0297386f, 0x1eaf7f87, 0x0c22edad, 0x154735ec, 0xa6b4b7}}}, + /* 5*16^31*G: */ + {{{0x0b3510d3, 0x13e7ef30, 0x0875b904, 0x062cce09, 0x1292885d, 0x10c32e16, 0x1422a362, 0x1fcff3f9, 0x23c493}}, + {{0x1ae89a47, 0x1a317621, 0x0e76f5c4, 0x13c6bc4d, 0x1e6d8f79, 0x0ecf277f, 0x108c309d, 0x153c8682, 0xadf456}}}, + /* 7*16^31*G: */ + {{{0x0b49a71f, 0x06348c04, 0x089f0e6b, 0x0dd6d8c8, 0x035ddac3, 0x09f5d579, 0x03b77966, 0x016629ba, 0x94406d}}, + {{0x10b249a9, 0x18e0ca26, 0x18f3e511, 0x04e4c394, 0x1e897d0e, 0x1e484837, 0x05e73481, 0x0fd0c9be, 0x61aae7}}}, + /* 9*16^31*G: */ + {{{0x00e50c32, 0x0e6f19e3, 0x11a1cff9, 0x0212e5d1, 0x08d3877f, 0x1b6fadf7, 0x1050cdc4, 0x087bd10d, 0x3c2ebf}}, + {{0x0a93c124, 0x117c48be, 0x1a326627, 0x1a118735, 0x028e7be2, 0x1c9e9017, 0x06719496, 0x14d8bd07, 0xa703d9}}}, + /* 11*16^31*G: */ + {{{0x03a2355a, 0x041ecef6, 0x1812641c, 0x0a37e6b8, 0x15f12996, 0x12dc4f62, 0x1ae7ce47, 0x1ae4f281, 0x987536}}, + {{0x1bd05276, 0x063ae260, 0x0eb7337c, 0x1ed8f8d0, 0x17b48b85, 0x18e0a4f2, 0x05c90f82, 0x1ace9e22, 0x12f19a}}}, + /* 13*16^31*G: */ + {{{0x12f3ec22, 0x0782a3e2, 0x0a3e29ac, 0x10db9ee3, 0x0ddddd1f, 0x1c58bf79, 0x11a3c674, 0x08134988, 0xd515ac}}, + {{0x05a2863b, 0x10a31759, 0x06e01bb2, 0x0afbe006, 0x0bd464cd, 0x12420029, 0x0cb87a97, 0x02844893, 0x51c048}}}, + /* 15*16^31*G: */ + {{{0x1971c857, 0x0cd0f4d2, 0x19824fe9, 0x133cdb57, 0x1cf3ddec, 0x1e61c5b0, 0x02eb8914, 0x0930bcb6, 0x70b9d}}, + {{0x0ac8dfc1, 0x1ce5b1ee, 0x15186abf, 0x107b43d8, 0x13cfb33a, 0x0857231b, 0x09421ae0, 0x037fe96c, 0xed8046}}} + }, + { + /* 1*16^32*G: */ + {{{0x1789bd85, 0x1e427e4e, 0x05fab0d5, 0x0bfefb85, 0x0766efc3, 0x17eac463, 0x199fee60, 0x137ddb6b, 0x447d73}}, + {{0x12e25b32, 0x03f19e4b, 0x1eb94003, 0x09372b4f, 0x0aff73d3, 0x0eca9d25, 0x07bb84ba, 0x15706826, 0x2d4825}}}, + /* 3*16^32*G: */ + {{{0x1ea6db68, 0x1f0ccc76, 0x098cb09c, 0x15b0ac10, 0x0f4f6ddf, 0x06fcb2ef, 0x05fd62c5, 0x07c07940, 0xf8b653}}, + {{0x0e760da9, 0x0de92d85, 0x17283b5a, 0x1ae1bb38, 0x03ec66bb, 0x16ed2855, 0x1218bc11, 0x1ebd888a, 0xc30f4e}}}, + /* 5*16^32*G: */ + {{{0x1924e753, 0x16aea75f, 0x1e1c9f19, 0x02e60e59, 0x1fb755f0, 0x18c394f6, 0x11f1523b, 0x1a6ab050, 0xf35289}}, + {{0x0b13a20c, 0x122dae17, 0x0b43c12a, 0x05f8ae52, 0x01bd8c56, 0x0450da87, 0x0fee4f7c, 0x03d8bd82, 0x75c178}}}, + /* 7*16^32*G: */ + {{{0x1018017e, 0x1cae5b39, 0x17c8f5c8, 0x083fffad, 0x14e01af1, 0x0c2fdb39, 0x1c5920d0, 0x0e9b4882, 0xcfd06b}}, + {{0x0e0dff50, 0x0573df26, 0x1de5dde8, 0x0060f0d6, 0x07950003, 0x19cac3ed, 0x044e040e, 0x1536e575, 0xb647b7}}}, + /* 9*16^32*G: */ + {{{0x192db860, 0x0640c82b, 0x06891ec1, 0x11251065, 0x1dbe9810, 0x0b68478a, 0x1344544b, 0x09895abb, 0x755e7}}, + {{0x00d09849, 0x0b3006dd, 0x109dde9f, 0x06e8c99f, 0x15bc2b29, 0x196c11c0, 0x19374926, 0x14ea75b3, 0xfe16af}}}, + /* 11*16^32*G: */ + {{{0x0a26ba6b, 0x0f7b4aaf, 0x1684b0ea, 0x1945492d, 0x0bbdedd2, 0x0606bf58, 0x05a5a284, 0x09986e59, 0x88fba8}}, + {{0x044972f8, 0x020a3c0f, 0x033f73a0, 0x153c51c0, 0x0788d484, 0x0d22da8a, 0x183f499b, 0x0c93a737, 0x512aef}}}, + /* 13*16^32*G: */ + {{{0x14720cab, 0x0e245214, 0x0e6c5f8e, 0x1d4ba82e, 0x06f2c1a1, 0x1b73aaae, 0x0fae3943, 0x197d80ab, 0xe1a0ac}}, + {{0x14b185c9, 0x16a29fab, 0x000953a9, 0x1454e3a1, 0x0bcbf084, 0x1c183bf7, 0x015060db, 0x1f6fd319, 0xe07968}}}, + /* 15*16^32*G: */ + {{{0x0c26c42a, 0x14147eff, 0x0c46ed8a, 0x17f6fc8d, 0x1e6a0249, 0x1ac498f3, 0x11f9436c, 0x10dcd4e7, 0xae93b}}, + {{0x19f808ca, 0x08319a1d, 0x0ab6d924, 0x1473ddeb, 0x00b37278, 0x11f6e0f1, 0x184ea50b, 0x1ba28f0f, 0x7028f6}}} + }, + { + /* 1*16^33*G: */ + {{{0x137de736, 0x15ec5d60, 0x02338907, 0x11aac30d, 0x0c18ea2f, 0x0a15c66f, 0x1cfa24dd, 0x02929399, 0x9022e3}}, + {{0x04c42ecc, 0x077ae042, 0x1a9d95fd, 0x126cd889, 0x0ce087f4, 0x1d822913, 0x0e519b42, 0x09e52094, 0x2fae5e}}}, + /* 3*16^33*G: */ + {{{0x109b01f5, 0x0b8365c6, 0x1cf01464, 0x1e6a3064, 0x1857af73, 0x169f8d7b, 0x0517ec3c, 0x1c60edfd, 0x6e5872}}, + {{0x0bcd5fde, 0x183ac6cd, 0x06a169f0, 0x02f3a9c1, 0x0f0ebc13, 0x0ea579df, 0x05c60330, 0x05d91aee, 0x4213c0}}}, + /* 5*16^33*G: */ + {{{0x0fe45b1f, 0x09cdba3f, 0x185a30ad, 0x02abf65c, 0x1df827bd, 0x0f1a260b, 0x1d412bf4, 0x1634bb47, 0x292220}}, + {{0x134bb026, 0x1f205c5a, 0x17504117, 0x06886099, 0x18d7ff7c, 0x1caffd74, 0x16bb8df1, 0x0a657e2e, 0xe316a0}}}, + /* 7*16^33*G: */ + {{{0x03abd540, 0x14283315, 0x059b790f, 0x0080ca96, 0x13a340e8, 0x07c39084, 0x1c2b0c89, 0x0900f489, 0x3644e1}}, + {{0x155da631, 0x0e37f0e6, 0x1be85378, 0x0ef9db4c, 0x1e293001, 0x02984fd0, 0x05d8470a, 0x0a1b784f, 0xec5a91}}}, + /* 9*16^33*G: */ + {{{0x09142ccb, 0x117e90f4, 0x01fb78c6, 0x0414b58d, 0x1b4824c9, 0x1c7a4c9d, 0x00e3956c, 0x15c2ff9b, 0xedfe7d}}, + {{0x0c593d75, 0x1ca8e98d, 0x14450bae, 0x08856d3a, 0x1beb81da, 0x0e95a7aa, 0x1c858615, 0x0245c1b5, 0xc88692}}}, + /* 11*16^33*G: */ + {{{0x0a41b208, 0x1ed38e32, 0x189c003c, 0x0e8eb9bd, 0x00de8e7f, 0x00135e75, 0x1a5661c5, 0x11680b34, 0x531196}}, + {{0x048e4b69, 0x08f0fcf0, 0x0da1dfda, 0x183b8048, 0x1da113b3, 0x0c0f19d9, 0x05e29b19, 0x0567b845, 0xb78d73}}}, + /* 13*16^33*G: */ + {{{0x095daae7, 0x1e80dae2, 0x1c0cef2c, 0x0dcdd8f8, 0x0e1d5af4, 0x15fb7ab0, 0x1653de88, 0x1e45ff74, 0xf65dd1}}, + {{0x02556738, 0x0a72d4ce, 0x0b366ca3, 0x0c301f3d, 0x04cd0eb0, 0x1f31be7e, 0x1ba0839b, 0x0419c36c, 0x9d71b8}}}, + /* 15*16^33*G: */ + {{{0x1afcf1ee, 0x1f7e0af1, 0x01a6846a, 0x155008e4, 0x007c60af, 0x1a405554, 0x0922d06f, 0x0fdb995c, 0xa6670e}}, + {{0x00c67fc8, 0x1c43855f, 0x0f3ce28d, 0x07312392, 0x1ac131ef, 0x1b97a4ab, 0x0bce8e57, 0x19274a38, 0xa7fd14}}} + }, + { + /* 1*16^34*G: */ + {{{0x04cd3397, 0x008a2e0a, 0x1457ad5d, 0x09820c32, 0x16deddc3, 0x16795a8a, 0x1c8e24e1, 0x00833db4, 0x73baff}}, + {{0x1adcb8e4, 0x0f79509c, 0x0984d250, 0x1df259f0, 0x1825e779, 0x08f460c7, 0x117da803, 0x0c692ef5, 0x1e97de}}}, + /* 3*16^34*G: */ + {{{0x161fb913, 0x1587ca90, 0x14c4a5df, 0x0048c2ad, 0x0d04e3e1, 0x046f225f, 0x0860d10e, 0x01867cc1, 0x45f833}}, + {{0x0c15c3bc, 0x06a40be0, 0x1f0cdcdc, 0x1a10f3ed, 0x07760f06, 0x003b6c5d, 0x01bbe03a, 0x0db7fad2, 0xc212cf}}}, + /* 5*16^34*G: */ + {{{0x0e393654, 0x177cb48f, 0x1b75f1d6, 0x1a97c3e7, 0x15991965, 0x100e45e6, 0x16ad97d6, 0x09359af7, 0x5544dc}}, + {{0x0f53206f, 0x1b085dfc, 0x15639cc8, 0x1dfd2e07, 0x15192241, 0x02dadc49, 0x152b0130, 0x112a10ff, 0xed3e85}}}, + /* 7*16^34*G: */ + {{{0x08a15dfd, 0x1f9acca1, 0x1ea79544, 0x1b75804b, 0x0f695741, 0x176aad71, 0x1dcd2cf4, 0x120c33dc, 0x2757b7}}, + {{0x1042c341, 0x04742067, 0x09c55b7f, 0x112f1479, 0x1500d176, 0x1a909e6a, 0x04b97325, 0x1aaa9856, 0xdf46d2}}}, + /* 9*16^34*G: */ + {{{0x1f840a5b, 0x1f6fa135, 0x0b52613b, 0x195b4ba7, 0x03ccd148, 0x10e6608a, 0x0f236610, 0x0fbca1c5, 0xe87243}}, + {{0x1377e86a, 0x0272c2a8, 0x0e59192e, 0x1468d9f2, 0x08bf5ac3, 0x048fb312, 0x185964ef, 0x11224e52, 0xf984bc}}}, + /* 11*16^34*G: */ + {{{0x136afd6a, 0x0ab54dc5, 0x1e078f52, 0x03f8a142, 0x1334a926, 0x1b6af379, 0x1700e4bb, 0x15749aee, 0xc56cdc}}, + {{0x13f87c26, 0x10435f77, 0x0331c8f9, 0x090764ad, 0x14ef566f, 0x0f58bfac, 0x01c334bb, 0x1c5e70d6, 0xd16056}}}, + /* 13*16^34*G: */ + {{{0x0cfd2cd0, 0x0d6cc069, 0x070304c7, 0x08266883, 0x0abb1239, 0x142c1f24, 0x0a1a73f4, 0x0e71e7fe, 0xd3d6e6}}, + {{0x194ae2dc, 0x02bce3bb, 0x1dbe3c53, 0x1f4ad185, 0x1e59b001, 0x147fb9be, 0x0da14db6, 0x0bf9a2b3, 0xff448f}}}, + /* 15*16^34*G: */ + {{{0x1ab7a64c, 0x0ac442ae, 0x026ade82, 0x011ad474, 0x1d406565, 0x196b911b, 0x101ec0c4, 0x110adc8b, 0x88f977}}, + {{0x1575f103, 0x02f4c708, 0x1b499ce8, 0x06012442, 0x09e5836c, 0x0d792bcb, 0x11d0d14c, 0x1ba8d6ab, 0x4a745c}}} + }, + { + /* 1*16^35*G: */ + {{{0x1fa4e33c, 0x1172fd98, 0x02632cc3, 0x077d8f16, 0x0fb98268, 0x023614bb, 0x16ef25d1, 0x17234984, 0x9cf646}}, + {{0x0e0d4563, 0x0e22f030, 0x10580c86, 0x00b04fd7, 0x01f319e2, 0x0712c5c1, 0x0a247902, 0x09b83ecb, 0x37b062}}}, + /* 3*16^35*G: */ + {{{0x06bf1e67, 0x0c5b0c66, 0x172bd8fa, 0x0cce93fc, 0x04e0f4c5, 0x129c13bb, 0x126675e9, 0x1bc2a36c, 0x83cb43}}, + {{0x099acc97, 0x13f74598, 0x1445a7a8, 0x0884597b, 0x018f8287, 0x00373122, 0x1be3bec6, 0x1449731e, 0xbce28c}}}, + /* 5*16^35*G: */ + {{{0x1c0f057e, 0x1856ba46, 0x154f7608, 0x10c50e03, 0x1022484e, 0x07e0af12, 0x02300cd0, 0x1cac19d6, 0x3ff3b3}}, + {{0x0817965e, 0x0a0fbed5, 0x1c05d88b, 0x0046dd88, 0x07843a01, 0x08b82bc3, 0x1e3dbdff, 0x0de776ca, 0x7f17ad}}}, + /* 7*16^35*G: */ + {{{0x125e69f1, 0x088a5a01, 0x08af2d45, 0x0f51e5a8, 0x0af99636, 0x0ef0b9eb, 0x00ff7686, 0x05bb1ffb, 0x6e9edb}}, + {{0x002b7e9b, 0x1070bf1a, 0x07ca06dc, 0x04e8a8f3, 0x1bff61c7, 0x0b55b2f9, 0x153aacd5, 0x02d9dff2, 0xc08222}}}, + /* 9*16^35*G: */ + {{{0x0288f038, 0x19297b35, 0x17fe082f, 0x0ed129d6, 0x02d32f08, 0x00cef376, 0x112fbeaf, 0x1d009883, 0x5ee280}}, + {{0x16f1ee6e, 0x02d55c35, 0x19b1bd07, 0x0f067531, 0x1eec011d, 0x0c37f664, 0x0e4a1301, 0x1f28cefc, 0xbcd969}}}, + /* 11*16^35*G: */ + {{{0x00c708c8, 0x05f992b6, 0x1c2a1aa8, 0x08609e5e, 0x0288c2c3, 0x1b2ec8ff, 0x15cdb7f8, 0x0dc0b840, 0xe1f016}}, + {{0x1896ed38, 0x18c6b9d9, 0x0d6802b9, 0x0abe45df, 0x13016fb6, 0x1195f451, 0x0d481111, 0x07d22d87, 0xe64765}}}, + /* 13*16^35*G: */ + {{{0x076edefb, 0x10784e52, 0x039f575f, 0x117b0020, 0x1c7badd5, 0x0d5a14bc, 0x1171fc48, 0x10f57ec6, 0x280896}}, + {{0x1d1b0ae0, 0x17a2b914, 0x00e4848b, 0x06360f7c, 0x141c44dd, 0x0cf5ec82, 0x064699f8, 0x1e67a766, 0x5d071c}}}, + /* 15*16^35*G: */ + {{{0x1344897a, 0x096ccde7, 0x1309a774, 0x1da60eb4, 0x1edab7b9, 0x0f429212, 0x132dc161, 0x1bc50320, 0xeb15b0}}, + {{0x05bfe7ee, 0x0cef41e7, 0x1f42e0ab, 0x0d3165f2, 0x12f85814, 0x157c66b9, 0x01c42262, 0x02d384cc, 0x96cdd}}} + }, + { + /* 1*16^36*G: */ + {{{0x123b716d, 0x137d6e02, 0x13869ae0, 0x0712cdee, 0x0df9e0d2, 0x03c9c68c, 0x14d3a297, 0x1c717194, 0xf81f5b}}, + {{0x12632401, 0x120017a8, 0x01e0cc11, 0x0eb0a075, 0x00328660, 0x094e9c07, 0x1b7c755b, 0x065383e0, 0xdc7f49}}}, + /* 3*16^36*G: */ + {{{0x19d19d8a, 0x062b4281, 0x09548561, 0x024f12a3, 0x1490a3b4, 0x161ae0b6, 0x18e16bdb, 0x0a1f6250, 0xa60084}}, + {{0x190d2c4f, 0x0caedd9a, 0x0995cf7f, 0x1c011f4e, 0x1ca84f0f, 0x0a2f3df4, 0x11cb23db, 0x180cf46f, 0x7b4b79}}}, + /* 5*16^36*G: */ + {{{0x096cac9f, 0x14c3d9ca, 0x11379c89, 0x0719d4b8, 0x10e1c59e, 0x04bcc7f5, 0x0d531930, 0x1632cfbe, 0xde5382}}, + {{0x0fa473d3, 0x070417ed, 0x1610455f, 0x07c528e7, 0x19f2bc2e, 0x1804c8e7, 0x06158b0e, 0x0f16d392, 0x9c47b6}}}, + /* 7*16^36*G: */ + {{{0x06807a23, 0x0594b1bc, 0x097fcf9f, 0x0040a2d4, 0x14ec8400, 0x1ccea88c, 0x04214d12, 0x0100fe55, 0xa7227b}}, + {{0x14115894, 0x0238cc1e, 0x0a337247, 0x1f02af6e, 0x075abe7b, 0x023c9050, 0x07a1176a, 0x04ba8ba7, 0xf55075}}}, + /* 9*16^36*G: */ + {{{0x044d14c0, 0x13cbfe10, 0x0a3cd796, 0x1956bf43, 0x01d39005, 0x1f39d1b3, 0x1659196a, 0x11a84688, 0xcd2b2e}}, + {{0x02496315, 0x0b056791, 0x0b33b3a9, 0x16de1973, 0x0f671fdd, 0x0f76ed60, 0x02893541, 0x1bf3610e, 0xf13012}}}, + /* 11*16^36*G: */ + {{{0x199a1566, 0x17a75891, 0x08a3da59, 0x18cab5fe, 0x19dd8f25, 0x1e4dc1ef, 0x1fad33be, 0x0991e1be, 0x11b2e8}}, + {{0x1c56bb73, 0x0d259e02, 0x16025a16, 0x16ab0819, 0x005cc824, 0x0b4c3cba, 0x05d7410b, 0x13b79446, 0x610376}}}, + /* 13*16^36*G: */ + {{{0x1ba6f34a, 0x084f5946, 0x1171be1f, 0x10d41fc4, 0x11485312, 0x1051f7cc, 0x01c1d676, 0x052be574, 0xfb6d19}}, + {{0x0bcf0452, 0x1af9e411, 0x1a16c7e6, 0x19f45b92, 0x191b9ecf, 0x07ea6253, 0x1b7678e2, 0x053af7e8, 0xf29b2d}}}, + /* 15*16^36*G: */ + {{{0x0a435427, 0x06516950, 0x1936d41d, 0x0021304f, 0x06651a69, 0x13b286c8, 0x0f042abd, 0x19820782, 0xff429f}}, + {{0x19853824, 0x12822869, 0x0e8368a3, 0x17dca694, 0x06876205, 0x04e42b0c, 0x16c25350, 0x0cd149d9, 0x2addf9}}} + }, + { + /* 1*16^37*G: */ + {{{0x07354b7a, 0x16ce3f3c, 0x045725e3, 0x1d94ad87, 0x0de1d022, 0x1a31f29e, 0x01208e5f, 0x0e9aefc1, 0x856854}}, + {{0x116e04c6, 0x0aa2015e, 0x15bf6f62, 0x1123b83f, 0x1728706a, 0x089d9537, 0x1edbbaf2, 0x16a17eb0, 0x20b50e}}}, + /* 3*16^37*G: */ + {{{0x1b26165d, 0x1b663fd3, 0x1dc4dfab, 0x07442bec, 0x092dea71, 0x090497e6, 0x199527a7, 0x18ea5647, 0x617344}}, + {{0x06b2a286, 0x04dfee5c, 0x1c5c6931, 0x13582dc6, 0x020b2989, 0x0885e8c1, 0x0d6926df, 0x02f486f0, 0xe99016}}}, + /* 5*16^37*G: */ + {{{0x10442770, 0x10dfbb32, 0x006eb440, 0x11ef4dc2, 0x0fc2e901, 0x00ed4f20, 0x088b6813, 0x1dcabf6d, 0xf8ac03}}, + {{0x1b00c82d, 0x11432788, 0x0107408e, 0x0c057f2a, 0x06d17a97, 0x03a8d9a7, 0x1a3a90db, 0x0cab33a3, 0x5a358e}}}, + /* 7*16^37*G: */ + {{{0x165460de, 0x1f036c37, 0x0fddee3e, 0x07f1a155, 0x08ea60c7, 0x1e5f1866, 0x1719b1b2, 0x16a4b792, 0x8a731f}}, + {{0x1f8dc207, 0x0c2cd0ef, 0x1423b8fa, 0x0cfc78a4, 0x04dc4358, 0x0aa5ffd8, 0x0c663d4a, 0x18bc556c, 0x585855}}}, + /* 9*16^37*G: */ + {{{0x151634a5, 0x0155d6fd, 0x1b549399, 0x1214f06b, 0x1967f3cf, 0x15d0166b, 0x0892fc29, 0x0c26551e, 0xa20b60}}, + {{0x1226afad, 0x1609bcaf, 0x1517b7c9, 0x08eafc79, 0x1315bc67, 0x0ff41b9d, 0x0676b4f5, 0x13ed2fb7, 0x9c43ce}}}, + /* 11*16^37*G: */ + {{{0x13ba54a8, 0x02191225, 0x0eaa5c1c, 0x164c6ac0, 0x1cc0ab58, 0x0761a7e2, 0x1c26450e, 0x127e24ac, 0x16f1f}}, + {{0x064f2889, 0x0be30fd3, 0x08ed39bb, 0x15e4ea8d, 0x0e658d93, 0x188df24e, 0x055dbca6, 0x0822b12a, 0x8bcd3}}}, + /* 13*16^37*G: */ + {{{0x07c16d94, 0x177249e7, 0x0a117f77, 0x103a1540, 0x0c31fe25, 0x1eb3e667, 0x11e23023, 0x0ce17a06, 0xe61586}}, + {{0x114810ab, 0x1a768cd5, 0x0910eefe, 0x0b9a3c8f, 0x0f0ee4e6, 0x15c9fa5b, 0x12fa316c, 0x15d3ce24, 0x65ca03}}}, + /* 15*16^37*G: */ + {{{0x13ce728d, 0x0b6e5332, 0x1c7342f3, 0x1b20fc50, 0x05347f4c, 0x04510b64, 0x08995568, 0x01671aad, 0xdcd37f}}, + {{0x17cacbcb, 0x0be89b4c, 0x076afae3, 0x19a68da5, 0x0d6f3caa, 0x1db159e3, 0x1061cb0d, 0x1aef9b49, 0x6574db}}} + }, + { + /* 1*16^38*G: */ + {{{0x12378c16, 0x0e36e0d8, 0x05588ab7, 0x0c0eaa8c, 0x1597d9e3, 0x1296b5fc, 0x0c46cc67, 0x0b382567, 0x1136b7}}, + {{0x13488127, 0x0facde85, 0x147338de, 0x095451ce, 0x1ecb2961, 0x15e307f4, 0x1f7427c2, 0x19e8a2d1, 0x7dec0f}}}, + /* 3*16^38*G: */ + {{{0x1b299740, 0x18736c13, 0x0f6c4d25, 0x1e8cfae2, 0x0ad48f40, 0x089bc9fd, 0x0cdb312b, 0x16e39ba8, 0x53893e}}, + {{0x1fff7509, 0x0f5378d9, 0x1f7a3354, 0x0265de43, 0x1dc8dd8a, 0x0714753a, 0x0f60e107, 0x0fd290bf, 0x27728a}}}, + /* 5*16^38*G: */ + {{{0x138000fc, 0x059e4ab3, 0x1c0ef04c, 0x1c4ee0f7, 0x0e5604e1, 0x1b5d78fd, 0x089d5f8d, 0x1baea99b, 0xdd64e9}}, + {{0x1df4ac12, 0x1d50e286, 0x07923e2f, 0x0ba04572, 0x079ffbe4, 0x0f1f0ce5, 0x0b25b7e2, 0x1d618526, 0x432193}}}, + /* 7*16^38*G: */ + {{{0x13878c4a, 0x1c10a8b9, 0x1470157b, 0x07a0790a, 0x11b21d88, 0x0e307254, 0x145bcb1a, 0x150fdffa, 0xff9845}}, + {{0x1488df68, 0x1d3423eb, 0x173faf1a, 0x066e8d6c, 0x1e8ddf1f, 0x12476ffa, 0x0a3e3f62, 0x1e949c48, 0x835b9a}}}, + /* 9*16^38*G: */ + {{{0x00f51524, 0x054dc40a, 0x0be1bf23, 0x1d6d42b7, 0x093de5fa, 0x1d184229, 0x0273a1d9, 0x1d17722c, 0x954e13}}, + {{0x05e30a69, 0x0fed9eca, 0x079f2f7a, 0x1d486228, 0x0cbcfa9e, 0x1121a3cf, 0x010764f1, 0x07ff2548, 0xecc836}}}, + /* 11*16^38*G: */ + {{{0x04f77287, 0x1bcc6a9e, 0x0c3678c7, 0x12a786d2, 0x00497412, 0x0862e0ec, 0x0e4f7f35, 0x1edf483f, 0xb2217e}}, + {{0x04e7b5da, 0x1d0253b9, 0x17a4f2e5, 0x13b8e738, 0x0c843d70, 0x1e7c469c, 0x0e8ad77e, 0x1c19cf9e, 0xfb5153}}}, + /* 13*16^38*G: */ + {{{0x05c723e9, 0x17a9cb64, 0x09e05c62, 0x0e775535, 0x15c351f9, 0x175748ae, 0x16b448b1, 0x162f6f37, 0x3c3950}}, + {{0x16834763, 0x11c3bafb, 0x1241ab97, 0x1b596af8, 0x0a8b0b01, 0x1dbf50c3, 0x036ed252, 0x0c441222, 0xb99b73}}}, + /* 15*16^38*G: */ + {{{0x1c18abeb, 0x18beb711, 0x09758a8d, 0x1b9a320e, 0x0a944d59, 0x097c225d, 0x136b477b, 0x0599f2c3, 0x803c7a}}, + {{0x029bfa78, 0x121cdf87, 0x19c8735a, 0x18887854, 0x14409ed7, 0x078b4e25, 0x04a1ac6b, 0x0814f2dd, 0x83fb50}}} + }, + { + /* 1*16^39*G: */ + {{{0x143e832a, 0x03b1778c, 0x01b7dc27, 0x0a15602f, 0x1f18e07e, 0x19d412c4, 0x146a43d5, 0x1174f854, 0xd2bf2}}, + {{0x1b20d37c, 0x0131d78a, 0x15451192, 0x193b72c0, 0x0e7ed27e, 0x10854a5a, 0x02b1c21e, 0x086277a0, 0xcac3f}}}, + /* 3*16^39*G: */ + {{{0x112c9666, 0x0f5625e0, 0x1ff37cd8, 0x118d86cb, 0x1531b1cf, 0x061adbec, 0x00b3f66f, 0x0bd72cff, 0x34e5e8}}, + {{0x192a3666, 0x0d0c29e4, 0x18e949ad, 0x0fdac783, 0x046330f4, 0x12bae65e, 0x0dae0a11, 0x06264434, 0xc0ce68}}}, + /* 5*16^39*G: */ + {{{0x11209502, 0x0b295f1a, 0x16499970, 0x02e4004b, 0x1e154594, 0x09f7848c, 0x018e9b12, 0x198b3e9b, 0x727362}}, + {{0x17042b0d, 0x13be8e9e, 0x09d82ef1, 0x1a6ff376, 0x11d20a18, 0x05c61674, 0x0d627c40, 0x04537575, 0x17b0f4}}}, + /* 7*16^39*G: */ + {{{0x0447f959, 0x0af3c945, 0x1c74da11, 0x0fb57504, 0x1eee9f94, 0x0a625da4, 0x13b25ce8, 0x0c00a94d, 0xa0c3f2}}, + {{0x168b671f, 0x01ce9244, 0x149cb26c, 0x0aa804b1, 0x08208b1b, 0x060865b1, 0x113ce0be, 0x0121c965, 0x508c73}}}, + /* 9*16^39*G: */ + {{{0x1b37e1d3, 0x10fcf812, 0x193788c0, 0x0c37c279, 0x1fd04107, 0x019df20a, 0x09e9032d, 0x063ef2b9, 0x7e81b2}}, + {{0x0155681a, 0x1afe5132, 0x10b8380f, 0x1097e563, 0x07c4e4ec, 0x04b67736, 0x144c497a, 0x0361d37d, 0xf3855a}}}, + /* 11*16^39*G: */ + {{{0x16c051a0, 0x04bb8afa, 0x16cf9b71, 0x1e5248de, 0x12abddcd, 0x0c736d87, 0x1b6128db, 0x038fb004, 0x8035e2}}, + {{0x12d0dd12, 0x00f5d97d, 0x02d88d58, 0x0fb8c613, 0x1d318b3e, 0x1f341bde, 0x0fbcdd76, 0x14896f45, 0xb8810}}}, + /* 13*16^39*G: */ + {{{0x1f12c69e, 0x1006184f, 0x194658f3, 0x0b5deb12, 0x0fcecafe, 0x18008102, 0x14cc1aeb, 0x1bfac314, 0x196908}}, + {{0x1d114831, 0x0998c820, 0x1ee21ae3, 0x05c66e3f, 0x1054eb6b, 0x0ef56e90, 0x18102fb8, 0x0d65f22d, 0x3f65bf}}}, + /* 15*16^39*G: */ + {{{0x0b89c5ed, 0x04c700fe, 0x1e9e31f9, 0x0a619ef2, 0x10f3577b, 0x10e90856, 0x0abd1b9b, 0x1d712c34, 0xdb77fc}}, + {{0x0d25b46e, 0x0ff8e3f7, 0x0266be96, 0x0d8f56d1, 0x1ad411f1, 0x1cdf264c, 0x173bb3cc, 0x070e39dc, 0x7fd1dc}}} + }, + { + /* 1*16^40*G: */ + {{{0x17f82f2a, 0x174e3aef, 0x1f7d0eab, 0x186b0e95, 0x113269e4, 0x16fa1b9b, 0x185fd588, 0x0acdd8e6, 0x8a535f}}, + {{0x023094b7, 0x0fcd0561, 0x031d9a71, 0x0a670c99, 0x092bfcde, 0x140c842d, 0x0f5cdf80, 0x108d1611, 0x455c0}}}, + /* 3*16^40*G: */ + {{{0x0b348fa0, 0x18a790bd, 0x0550777e, 0x1c48b20a, 0x0b4bce0f, 0x1191b612, 0x00b70a88, 0x07bbbd71, 0x86eac9}}, + {{0x0da51cee, 0x171c04aa, 0x13fba293, 0x0db2c6a3, 0x146716c2, 0x17cf46b7, 0x1635690d, 0x0a797789, 0x948f38}}}, + /* 5*16^40*G: */ + {{{0x19222c03, 0x17a0ffe4, 0x197840de, 0x19cefd0f, 0x1f407948, 0x1ebc242c, 0x0ab8fd79, 0x175f3f67, 0x8bf09e}}, + {{0x0a72bb54, 0x0a2fba17, 0x08387528, 0x1d81c3bc, 0x1ba309c9, 0x18edf3f2, 0x09cced22, 0x15fc5c4f, 0x509cba}}}, + /* 7*16^40*G: */ + {{{0x11ae9300, 0x029d160e, 0x1120a02d, 0x188e08eb, 0x1735b5e1, 0x05d6d179, 0x1f18644c, 0x1976fce1, 0xe85e2d}}, + {{0x1546e25e, 0x1506fee8, 0x030c6edc, 0x0fc30bbf, 0x02707deb, 0x1dadc11e, 0x02ff1ee9, 0x14daa39c, 0x451aaf}}}, + /* 9*16^40*G: */ + {{{0x05260cb8, 0x092eaab0, 0x0c854bc9, 0x1e95019d, 0x1dbf6836, 0x13ed0dd3, 0x1e0a8fc0, 0x1e451925, 0x3f5fb0}}, + {{0x1852c964, 0x17da5a20, 0x17b0cc9c, 0x1d0ea3f8, 0x183f2fa3, 0x0f0a9b33, 0x061c38e3, 0x1b5b4933, 0xc55834}}}, + /* 11*16^40*G: */ + {{{0x1a1cd60f, 0x15222216, 0x0c24ba92, 0x0d315398, 0x0002b9f9, 0x083a5a6d, 0x06595ebb, 0x045631b3, 0x336856}}, + {{0x0fd57d67, 0x1fb9bb28, 0x142e2c92, 0x1eb49978, 0x1af175fe, 0x06006f53, 0x1366ea16, 0x13de248f, 0xd42f50}}}, + /* 13*16^40*G: */ + {{{0x17576342, 0x029db75d, 0x06488abc, 0x19110673, 0x179d95b2, 0x1cec4b04, 0x0203df43, 0x0b811e00, 0x4813eb}}, + {{0x17376316, 0x060aaf5c, 0x1aa413d9, 0x1b8cfaa0, 0x1524aca2, 0x0b424719, 0x0903d980, 0x1a846748, 0x043f}}}, + /* 15*16^40*G: */ + {{{0x1f69b2be, 0x1b38b8ef, 0x04447027, 0x03ee9db8, 0x06e56ba4, 0x16ddd71c, 0x05ebc4c8, 0x1f34b5d3, 0x80c3f1}}, + {{0x0102d2f5, 0x0825cbe2, 0x0dea2fe2, 0x16e966b9, 0x15a9bf14, 0x113b2d8e, 0x1a14a603, 0x0814013b, 0xa9321}}} + }, + { + /* 1*16^41*G: */ + {{{0x0476c81d, 0x041bfa7f, 0x194f57a7, 0x06061d33, 0x0a366b7a, 0x06939ed4, 0x08066bdf, 0x1bfb9683, 0xad6090}}, + {{0x0e6705dd, 0x0c55e427, 0x0c1237e0, 0x1fb86c9e, 0x1d8a8393, 0x1ae1662d, 0x047ab335, 0x1ba91e99, 0x77b5d1}}}, + /* 3*16^41*G: */ + {{{0x02725490, 0x11239be7, 0x12d66402, 0x06480c47, 0x1863c4ac, 0x15299d84, 0x05f28ab6, 0x176e35ad, 0xd90b45}}, + {{0x0feb1299, 0x07c27c25, 0x1119b32c, 0x180f7fe7, 0x0cbd80cd, 0x1ab439bc, 0x143c2762, 0x11d83766, 0x332692}}}, + /* 5*16^41*G: */ + {{{0x1e933668, 0x1b59d32b, 0x1aeafc29, 0x05b099f0, 0x106befb0, 0x1c9d7d0f, 0x1f1eb014, 0x02e62427, 0xac2592}}, + {{0x12776fb5, 0x173bfb39, 0x07879e85, 0x0c83138d, 0x0ed7c6f8, 0x009f75ec, 0x02ea143b, 0x070e1b75, 0x6c79a0}}}, + /* 7*16^41*G: */ + {{{0x128de7e3, 0x130be090, 0x1aa65b66, 0x08558757, 0x031bf868, 0x07ded3da, 0x0ea21cc8, 0x095d2f3e, 0x7bc337}}, + {{0x0e6e5e29, 0x1d059975, 0x10333c19, 0x05b67369, 0x1acbd55f, 0x1bd73725, 0x19778031, 0x048c10a9, 0xb431f0}}}, + /* 9*16^41*G: */ + {{{0x035e057d, 0x1659191c, 0x162696d2, 0x1e21b5ed, 0x1119329c, 0x0397e1a0, 0x0ac9a2f2, 0x128a75c0, 0xbf9c14}}, + {{0x0da20fea, 0x1ab25941, 0x1711e6db, 0x173c3038, 0x1a542440, 0x189f82e3, 0x0f83ce14, 0x13e4be47, 0x92acb8}}}, + /* 11*16^41*G: */ + {{{0x021d6584, 0x1566be10, 0x0cf67974, 0x00bac887, 0x1014ef27, 0x1ed1ad6f, 0x1e2a5ba5, 0x0736af09, 0x55bf08}}, + {{0x0ed744ea, 0x0ab27a14, 0x19696a03, 0x1c284055, 0x07dcf089, 0x1fb5d45e, 0x133c9eb2, 0x067c96c3, 0x3d9807}}}, + /* 13*16^41*G: */ + {{{0x01068c5e, 0x0b4efb72, 0x195cf437, 0x0bdcdc97, 0x1d4872a4, 0x10a73c0a, 0x15467cab, 0x02ca66f1, 0xfcf24e}}, + {{0x07c19d75, 0x10fa29f9, 0x052156dd, 0x0ed49650, 0x0e7aee91, 0x0f10dac9, 0x1f8d719d, 0x1ca66dff, 0x186bb0}}}, + /* 15*16^41*G: */ + {{{0x020da860, 0x1becaf83, 0x12744022, 0x08a35490, 0x11f2f843, 0x1b29a1ec, 0x1fb287f6, 0x1a05ea2c, 0x7bc280}}, + {{0x07aac76d, 0x11488208, 0x1058cbaf, 0x03345fb9, 0x0e6e0f2e, 0x15fd382f, 0x07978989, 0x0ef777a6, 0xb33f6d}}} + }, + { + /* 1*16^42*G: */ + {{{0x13c4a205, 0x097961b4, 0x042a1229, 0x15bf13ea, 0x129fcde1, 0x0ab83adc, 0x0f139199, 0x0a2c60b7, 0xb6e06c}}, + {{0x1db36d05, 0x1bfa6c32, 0x0aa7e1d4, 0x13283350, 0x0d73b63f, 0x189373cf, 0x0fd71787, 0x0f843664, 0xbdb427}}}, + /* 3*16^42*G: */ + {{{0x19e27907, 0x17c10fb7, 0x167935a4, 0x15a96711, 0x1bd68771, 0x0eaeb7ef, 0x1139ace5, 0x07f08483, 0xed9e4}}, + {{0x0e78c4fb, 0x09fa7a83, 0x0e86417c, 0x0a39fd71, 0x00e0ce91, 0x07ec7589, 0x0d1fd6f0, 0x095fed64, 0xb5af87}}}, + /* 5*16^42*G: */ + {{{0x15b38f54, 0x1682b929, 0x0bc1f38d, 0x150c1cb9, 0x0e1f92e2, 0x146da47f, 0x1df71549, 0x0200edb1, 0x57a7e4}}, + {{0x045f2809, 0x1d3c0f31, 0x01fae9d7, 0x0edc7352, 0x0dd21dfd, 0x0511de41, 0x14906532, 0x00791d95, 0xfd7f0f}}}, + /* 7*16^42*G: */ + {{{0x07a79593, 0x17f5dfcd, 0x17125e51, 0x14e493a4, 0x05cf3347, 0x0d92c665, 0x16fbd4b6, 0x1c5e7deb, 0x24799a}}, + {{0x10920d55, 0x11c46bae, 0x1ac4e635, 0x086c3f37, 0x1e300999, 0x08d4e9b1, 0x0deccb0f, 0x04c5d90f, 0x9436b5}}}, + /* 9*16^42*G: */ + {{{0x0bf5abdc, 0x010b75a8, 0x02d94198, 0x19a75f7a, 0x15d60456, 0x08e58406, 0x009bb4c4, 0x18d1098e, 0xf15017}}, + {{0x0def85b7, 0x1aef15c5, 0x0e15612d, 0x18ceb84f, 0x1e232cbd, 0x1a0f1fe2, 0x0aa3b360, 0x03858be0, 0xdea7ef}}}, + /* 11*16^42*G: */ + {{{0x1e78e9b1, 0x0f92958f, 0x10507a1a, 0x11cdb89d, 0x0dfcc897, 0x018fba89, 0x1aa9b83e, 0x01f13697, 0xe196e2}}, + {{0x0a77eed7, 0x00bab0fe, 0x1b4d7d11, 0x1a02257d, 0x0ed9a908, 0x045f3b59, 0x1698a990, 0x10bf0350, 0xa5d66d}}}, + /* 13*16^42*G: */ + {{{0x1b1cb64b, 0x17719f2b, 0x02b0f55d, 0x13ca4ac3, 0x1ed14d60, 0x1e6b8a9c, 0x0c0bce5f, 0x1bcd8360, 0x7779f5}}, + {{0x1aba3aab, 0x070c68e5, 0x0aa54cf6, 0x10528479, 0x0e3fae2a, 0x189a53d1, 0x1afab7ea, 0x07e8e987, 0x9a842}}}, + /* 15*16^42*G: */ + {{{0x11d1b492, 0x16c2c3b4, 0x0669bd4f, 0x00c31840, 0x08ce8dfa, 0x16cd5759, 0x0bc4797d, 0x097c8474, 0x8605b9}}, + {{0x18ac6598, 0x18ebbdfb, 0x07a49715, 0x06a4da90, 0x1d1a8ee2, 0x170610a1, 0x1d63cfbd, 0x050fbcea, 0xa8e561}}} + }, + { + /* 1*16^43*G: */ + {{{0x09aa52df, 0x06afa725, 0x0a989fcf, 0x08a56368, 0x1ece618c, 0x00c4ecc8, 0x0fddb6f1, 0x192fec11, 0x45a511}}, + {{0x125ec16c, 0x1a95e890, 0x0a55739e, 0x03364fa4, 0x05ad25a9, 0x19bfe5b1, 0x0db4ff8c, 0x18ee7d53, 0x73be0e}}}, + /* 3*16^43*G: */ + {{{0x0e75bc7f, 0x0b3a9f7d, 0x1dfec7d9, 0x0e2e1b6d, 0x14c7b95c, 0x07890be6, 0x0d0e3bd0, 0x09fce572, 0xb57ac}}, + {{0x0972e9a9, 0x078b96e8, 0x127f1881, 0x12d81c80, 0x094fab1f, 0x1a67d2bf, 0x0ed7ca30, 0x104ef53e, 0xceedbf}}}, + /* 5*16^43*G: */ + {{{0x033125ff, 0x1ba19e7c, 0x16a05084, 0x0aaf60b4, 0x0ae99354, 0x016ce50e, 0x05233d1a, 0x1f6dc97a, 0x1178b3}}, + {{0x18486abd, 0x007cb84e, 0x195346fa, 0x115b9a11, 0x10ed10dc, 0x131bf518, 0x056ce0b7, 0x1d53757b, 0xdfd697}}}, + /* 7*16^43*G: */ + {{{0x1662d955, 0x19b4ae67, 0x033913ce, 0x09ad0b69, 0x15693844, 0x1dbf4693, 0x041fe2a0, 0x104df29d, 0x8ac7a0}}, + {{0x046b3dae, 0x03516df3, 0x1b04e36f, 0x09038b7a, 0x19ad9e3f, 0x1291a65a, 0x0c73275f, 0x1241e664, 0xc80f40}}}, + /* 9*16^43*G: */ + {{{0x088803e5, 0x06c3cd6f, 0x0d1972df, 0x156f9c1a, 0x09e02cc1, 0x1d43802b, 0x08446adf, 0x050b3bbe, 0xc0f48b}}, + {{0x076619ee, 0x14991014, 0x00a3b6e9, 0x1c9c0e17, 0x0d7d3932, 0x12393f30, 0x08da7269, 0x16df1079, 0x3d4326}}}, + /* 11*16^43*G: */ + {{{0x1e1f515c, 0x0b6b384c, 0x194e6bea, 0x09146442, 0x1b8c0e2b, 0x047087fb, 0x19b68067, 0x01e06a2e, 0x2ce870}}, + {{0x052eed6e, 0x08c9b24c, 0x10f54b25, 0x13b9a7c5, 0x15d2ca7a, 0x17a17bf7, 0x129eeb2c, 0x09e76bd8, 0x73879f}}}, + /* 13*16^43*G: */ + {{{0x04dcf274, 0x0d51bbaf, 0x0b3a8911, 0x0400d059, 0x0ca1d807, 0x0dd87ebe, 0x04245178, 0x0c3b96f8, 0xfac442}}, + {{0x112f0472, 0x1b4c3007, 0x11652c58, 0x004f8c4e, 0x097bd732, 0x11eaea77, 0x02a1f31c, 0x18c2acd5, 0x9713fd}}}, + /* 15*16^43*G: */ + {{{0x1dc39d21, 0x1af25b55, 0x06b71a0a, 0x0e7d7a81, 0x12813683, 0x0f21d0cc, 0x18011964, 0x02cb6807, 0xf891e6}}, + {{0x05ca579f, 0x0c8470be, 0x11809535, 0x12fd89ea, 0x1c43b73a, 0x1c54716d, 0x13b462ba, 0x162577bf, 0x129f53}}} + }, + { + /* 1*16^44*G: */ + {{{0x1076f57b, 0x0678d5cc, 0x12b181ca, 0x170dc79d, 0x0a53f030, 0x11a80e79, 0x1e72e49f, 0x0ac91018, 0x20e118}}, + {{0x0da7afe6, 0x0c1df6dd, 0x186dc7a1, 0x01b93681, 0x1e9979fe, 0x01f1fdb6, 0x1bdcc6f7, 0x0a55886f, 0xff67b3}}}, + /* 3*16^44*G: */ + {{{0x0b661da4, 0x04f1d76a, 0x0a129721, 0x14a358c9, 0x01a21940, 0x1fec8183, 0x1b3a3df1, 0x0b770cc0, 0xffca2a}}, + {{0x0f9b8a5a, 0x0c241af5, 0x1a1fdbe2, 0x1f0f5bca, 0x06c8c478, 0x04d0a47a, 0x172294f3, 0x1c656e39, 0xce1cb0}}}, + /* 5*16^44*G: */ + {{{0x1c8cfd22, 0x0560f09c, 0x0daf960f, 0x160ce36c, 0x1354a4e2, 0x1a8a86d6, 0x1aad8d94, 0x1dbff822, 0xff209c}}, + {{0x13bc5535, 0x1c4d8a74, 0x1a12e508, 0x1e972592, 0x1f1c80d4, 0x00e92667, 0x1df881f5, 0x12e8d3a1, 0xad79f3}}}, + /* 7*16^44*G: */ + {{{0x0f4e983e, 0x003f2c2c, 0x05fddf3a, 0x1cdd90e0, 0x14b156d9, 0x0040699d, 0x0ea56181, 0x05a160f3, 0x33d5f0}}, + {{0x11ea37a9, 0x0b86dc3c, 0x18c3255b, 0x035524b2, 0x1a1eb7a7, 0x0b0b2add, 0x1e11cf0f, 0x0eda7388, 0x1eb5a}}}, + /* 9*16^44*G: */ + {{{0x01e52a73, 0x14ad3cfb, 0x01686f2d, 0x0622d92e, 0x15e65d0e, 0x1a6cd6dd, 0x1a42a7a5, 0x07b4c4c2, 0x8f1bd2}}, + {{0x0bea8f2e, 0x1ed0a28f, 0x06142a15, 0x0a05cc96, 0x1eade590, 0x0f2183a1, 0x02e2e1da, 0x0c7275b5, 0x4c7a8f}}}, + /* 11*16^44*G: */ + {{{0x1d2bc078, 0x0217f617, 0x1cfbd696, 0x00ec0a53, 0x080aec4a, 0x0c5bed6c, 0x1fcfb98a, 0x1fdef6c6, 0x963bc9}}, + {{0x1afb8657, 0x0ed918fa, 0x10e8f09f, 0x180851e8, 0x0a4f1c5e, 0x128494c0, 0x188a028f, 0x07f9a3ce, 0x7ed338}}}, + /* 13*16^44*G: */ + {{{0x0fb608ad, 0x038f3b75, 0x03f64e9a, 0x00aca9b1, 0x0bc49748, 0x16ee5be4, 0x011398c6, 0x15b0c3b5, 0x89fe6d}}, + {{0x064d4dad, 0x00a0373c, 0x1c2a1ed8, 0x13aa27c1, 0x1df39aea, 0x1effdb92, 0x03f21ed5, 0x10463e9d, 0x289827}}}, + /* 15*16^44*G: */ + {{{0x19ae4a29, 0x18c4c0d8, 0x08ca82c1, 0x1fb4dd44, 0x06984df2, 0x1d62708b, 0x1d654435, 0x0fe77af2, 0xc34804}}, + {{0x0eb09235, 0x04acd626, 0x126bafcd, 0x05d33e0a, 0x1ae9a842, 0x06e90706, 0x11584f6a, 0x1e40ad43, 0x584781}}} + }, + { + /* 1*16^45*G: */ + {{{0x19273a8f, 0x08a29744, 0x13f552b7, 0x1a8f1cd2, 0x1dac93fd, 0x163fefeb, 0x09ec0c63, 0x1f0e4740, 0x5c9cc4}}, + {{0x1ce80d6e, 0x0ed6534a, 0x06b2ad6b, 0x006ceb42, 0x0af964f0, 0x0c4e9b84, 0x0966a09d, 0x0f43bfda, 0x84efe0}}}, + /* 3*16^45*G: */ + {{{0x0883e382, 0x0464c2a2, 0x154dbce3, 0x009f9dea, 0x07431d06, 0x001ca900, 0x01716f89, 0x12577bfb, 0x5ac8e1}}, + {{0x1dfeaadc, 0x09b9ecde, 0x13674b94, 0x0dd9427a, 0x03976de7, 0x1ff9784b, 0x1200e723, 0x00098f51, 0xfcb7e5}}}, + /* 5*16^45*G: */ + {{{0x0f01a3e8, 0x052183bf, 0x120253af, 0x16ca865c, 0x07362c6e, 0x0ea2706b, 0x0460b545, 0x1316f224, 0x99dc06}}, + {{0x00f61114, 0x14322ff2, 0x1e3ca514, 0x0ce069af, 0x00044b7a, 0x0388b8ec, 0x0af1a5eb, 0x1ba47730, 0x67c69c}}}, + /* 7*16^45*G: */ + {{{0x0cd535ab, 0x01fbd802, 0x1d9370ce, 0x09b107d0, 0x1b9f3772, 0x01abe7e7, 0x18591009, 0x0c31c080, 0xabe2f3}}, + {{0x117b9c1a, 0x0388d9a2, 0x0b237664, 0x1cf43187, 0x1f7957fd, 0x1f959016, 0x0a4f7836, 0x0996eab6, 0x4f02d6}}}, + /* 9*16^45*G: */ + {{{0x0909970c, 0x1a5b359b, 0x19b93836, 0x11b74b33, 0x0099e451, 0x1d8fbbf3, 0x1c84df1b, 0x1af1873c, 0x227cd0}}, + {{0x1f809727, 0x02d25718, 0x0e67b10a, 0x01d87efd, 0x15defa21, 0x043a0e7f, 0x04761f5b, 0x0e390327, 0x2225e7}}}, + /* 11*16^45*G: */ + {{{0x09e65b59, 0x0cd6fe4c, 0x113fddf3, 0x02045efa, 0x1053b7a4, 0x14985466, 0x16da09fb, 0x10415db8, 0x363146}}, + {{0x09b4c2cf, 0x0050b213, 0x116dba72, 0x0792076b, 0x07fc1c14, 0x1c7c9011, 0x0a4a3a09, 0x0c42f12e, 0x1d87db}}}, + /* 13*16^45*G: */ + {{{0x0d4c2506, 0x0bd8ac5e, 0x07a7ebc0, 0x18bb8fe3, 0x11fec5b6, 0x14670c4e, 0x028f9d29, 0x16cd0d63, 0xf65ed6}}, + {{0x1913dfac, 0x0296e129, 0x15950af3, 0x11df8699, 0x0e7bd412, 0x0e17e9bb, 0x0ba14957, 0x0d065175, 0xd6d0bc}}}, + /* 15*16^45*G: */ + {{{0x1b47a80b, 0x0f27cba9, 0x0925d5e0, 0x0f8b4cc8, 0x1dba8ff9, 0x0e13b7d5, 0x0d5ca776, 0x1f423ec2, 0x66a0de}}, + {{0x1f795e8b, 0x1b8cafc7, 0x1bb74803, 0x014850a4, 0x0f474c23, 0x0f92b0d7, 0x09072b63, 0x0dbc6f59, 0x3e24aa}}} + }, + { + /* 1*16^46*G: */ + {{{0x08523eb3, 0x1eecd599, 0x1b1b12b9, 0x1474eaaa, 0x1cde3351, 0x0c22279e, 0x16ad1ab0, 0x1d7f1516, 0xbaffd4}}, + {{0x15acf387, 0x0bc18066, 0x122dbb86, 0x02399f7e, 0x0c09c245, 0x0759bcad, 0x1a0c00ea, 0x18bb792b, 0xfa93d}}}, + /* 3*16^46*G: */ + {{{0x14737641, 0x004cda77, 0x10b84eb4, 0x158182cd, 0x03fb71af, 0x1a891b2b, 0x07b5dde2, 0x04488391, 0x91b445}}, + {{0x0101bbe0, 0x1289594f, 0x01df40fc, 0x0fb8ccdc, 0x1b428c9d, 0x11ad5817, 0x05d8b04c, 0x17a6ffb5, 0x3f4463}}}, + /* 5*16^46*G: */ + {{{0x06dd01df, 0x1515d5c1, 0x03fbee71, 0x1dfeeca7, 0x09165743, 0x1363e434, 0x01ea8dfa, 0x0bbd05b6, 0x296d13}}, + {{0x0a3a0dc8, 0x0a869905, 0x199bd812, 0x15ec31cb, 0x177cadff, 0x094bbb63, 0x1790ae1c, 0x1bb25c28, 0x14054e}}}, + /* 7*16^46*G: */ + {{{0x1650f5dd, 0x13f37836, 0x046cb231, 0x1fc24843, 0x04a9654f, 0x0178f8cf, 0x08c63c4f, 0x1e7226cf, 0x4b0942}}, + {{0x1aeddc6d, 0x1752de63, 0x19ce98b0, 0x18cf05c9, 0x1c25f023, 0x0080ab09, 0x0f038157, 0x14c6cd95, 0x7432aa}}}, + /* 9*16^46*G: */ + {{{0x04e4a96f, 0x11baf478, 0x1956c51e, 0x10c5686a, 0x0e4af188, 0x0dc7e269, 0x046a0cfb, 0x14c5fd98, 0x36377}}, + {{0x11e08cdb, 0x1d7dbf02, 0x0244c9a2, 0x13184286, 0x06263840, 0x062abc2a, 0x1e0e364c, 0x03a6a9fb, 0xa1de19}}}, + /* 11*16^46*G: */ + {{{0x079b5a59, 0x00fe9f0b, 0x1a798a85, 0x03d13d64, 0x03251c62, 0x16ab84ec, 0x058af2ef, 0x1ee61ebc, 0xa1041a}}, + {{0x0c5514a3, 0x0695a011, 0x0b19b676, 0x00d21c3d, 0x02afbfb3, 0x086c39de, 0x0c650899, 0x0d551eb1, 0xad4217}}}, + /* 13*16^46*G: */ + {{{0x0ddd597b, 0x1746d836, 0x015d637a, 0x1262e199, 0x12007d88, 0x0d687cf4, 0x191c0cdc, 0x15a163ca, 0xda2167}}, + {{0x1de7fa04, 0x140b93f1, 0x13e7d189, 0x1c54a428, 0x0ebf6cdd, 0x180753cc, 0x14d87fd9, 0x16c4a8dd, 0xa21992}}}, + /* 15*16^46*G: */ + {{{0x13f7dbb0, 0x09a51115, 0x0fca7026, 0x1c47b84d, 0x0f29df4e, 0x1dc390b2, 0x19e2f218, 0x1846fed8, 0x1c3fdb}}, + {{0x12e16d32, 0x1265ee4b, 0x083e2b75, 0x0c8c7000, 0x118d41f0, 0x129ca525, 0x004fc2ba, 0x0206f253, 0x39260f}}} + }, + { + /* 1*16^47*G: */ + {{{0x1a111101, 0x1a9046c5, 0x16cf17e0, 0x1e1634ed, 0x04c96479, 0x11a692bf, 0x1d9bb48a, 0x0131f9da, 0x6ad2a}}, + {{0x1fb37ef4, 0x0d3dd4ea, 0x03a26bb0, 0x053b056e, 0x162a0de4, 0x000ddcf5, 0x18d56693, 0x038b1f0b, 0x2d5b8b}}}, + /* 3*16^47*G: */ + {{{0x102bef6f, 0x17e1c23b, 0x0c7b90dd, 0x1c9e308a, 0x0d475bba, 0x05eb35ec, 0x15c813de, 0x0aad8779, 0xf1a2ca}}, + {{0x0f6c1ca3, 0x0d968fec, 0x154ad004, 0x08fd503f, 0x00168b0b, 0x0a0bee01, 0x04fb7d15, 0x15e09106, 0xb39b59}}}, + /* 5*16^47*G: */ + {{{0x00455367, 0x030147e5, 0x1584f820, 0x09e59049, 0x11851e6c, 0x00b2c75f, 0x00c3b864, 0x093fc770, 0xe924ad}}, + {{0x08257e92, 0x1e8c67c1, 0x099d4ad7, 0x1463549f, 0x1bb6f52d, 0x029c9eb7, 0x1b55d482, 0x12f34287, 0xfcc97d}}}, + /* 7*16^47*G: */ + {{{0x02f8f1e7, 0x08f849ca, 0x147e78ba, 0x0954ba9b, 0x122f68dd, 0x09a882fd, 0x09be802e, 0x0fb8bee0, 0xf49d9c}}, + {{0x114d9972, 0x1114558c, 0x135ea0e4, 0x0002789c, 0x0f67901b, 0x09d9dcca, 0x12b9ab97, 0x08407c75, 0xf5585d}}}, + /* 9*16^47*G: */ + {{{0x1b219a79, 0x19d4b3bf, 0x0609e9de, 0x19a882fd, 0x189e65c4, 0x01aabaa8, 0x1522c38f, 0x007c8d53, 0x28b04d}}, + {{0x102dbe24, 0x05fbe6c8, 0x0012f97e, 0x0cd99f0c, 0x0206b861, 0x12b90c1f, 0x1c51673f, 0x13cb4299, 0xf658da}}}, + /* 11*16^47*G: */ + {{{0x17774af9, 0x14116ce2, 0x1182b62c, 0x0d74ca22, 0x0efb54c1, 0x01c94435, 0x1a4f5a14, 0x17cf983f, 0x3f4766}}, + {{0x1d4de990, 0x1e6bfb26, 0x0dcc9bfd, 0x1299fbf3, 0x05f511ca, 0x1c483737, 0x12e8eac5, 0x1ad4e663, 0xcc810d}}}, + /* 13*16^47*G: */ + {{{0x08e57705, 0x020cf8f2, 0x1356639e, 0x1d6ff590, 0x1361721c, 0x0d5a0eb7, 0x19e47cab, 0x00581f1d, 0xe3249e}}, + {{0x18caec0c, 0x0a58cf41, 0x1ce10882, 0x128bae2c, 0x06b5a501, 0x1c60f924, 0x141f72dd, 0x10e026d2, 0xa66665}}}, + /* 15*16^47*G: */ + {{{0x125b93ac, 0x1c5e757d, 0x01fe34b1, 0x0404a20b, 0x1b4e917e, 0x13b49efd, 0x1872f7e7, 0x017bf6f2, 0xa68958}}, + {{0x0f589aab, 0x11e8e26b, 0x113f4eba, 0x03f02fb3, 0x19ff2fcf, 0x1780af82, 0x00faa9fc, 0x12969e0f, 0x4657ca}}} + }, + { + /* 1*16^48*G: */ + {{{0x113728be, 0x07907fd9, 0x11ae529b, 0x072b2347, 0x15fc5964, 0x1fc1a218, 0x09d89cdb, 0x0ef4f092, 0xa6d396}}, + {{0x0357f5f4, 0x15d5c19e, 0x010166fc, 0x15241845, 0x1ecdf824, 0x1d5e9693, 0x00599ae2, 0x0e936171, 0x674f84}}}, + /* 3*16^48*G: */ + {{{0x0f15d864, 0x02a5ab4e, 0x13234f30, 0x0dfb8d43, 0x0cf35240, 0x1673df13, 0x0c36bf23, 0x1af8bbdb, 0x7ef66}}, + {{0x140907fe, 0x0312a13b, 0x1392a2d5, 0x0e1c7639, 0x1505e9f4, 0x062910fe, 0x1a941b50, 0x0bb713bc, 0x2db332}}}, + /* 5*16^48*G: */ + {{{0x17c7c05e, 0x14a8a1e0, 0x19505ab1, 0x07972a59, 0x08c0bb28, 0x1397baf9, 0x118053ce, 0x0bf80db8, 0x82df4e}}, + {{0x18fff26b, 0x0b09e816, 0x0b6cc02e, 0x0bb28d08, 0x1cbd1cf1, 0x0b10890b, 0x08289d48, 0x193192c8, 0xe4e188}}}, + /* 7*16^48*G: */ + {{{0x140368b0, 0x0570ea0a, 0x1ba52760, 0x09845f1f, 0x07a62132, 0x0dc69c72, 0x11a9f679, 0x13782561, 0x261efc}}, + {{0x1deb011f, 0x1d692acd, 0x06d74c04, 0x0817c3c7, 0x1ff797e3, 0x02966b27, 0x13a7f722, 0x1b7c70df, 0x8a9d2a}}}, + /* 9*16^48*G: */ + {{{0x15eb8034, 0x0819f4a8, 0x1a3292bc, 0x1666bead, 0x1692df30, 0x1f2cecf3, 0x1e4526a9, 0x1aef4584, 0x6d48df}}, + {{0x1ab0ce30, 0x039843d2, 0x0fa2587a, 0x0421d454, 0x14763080, 0x1cb24f02, 0x04bcf579, 0x08a2cbba, 0x3cb472}}}, + /* 11*16^48*G: */ + {{{0x140535c8, 0x08a1efe2, 0x036c4fad, 0x014ac619, 0x14e6f65f, 0x11fda7e2, 0x048e9244, 0x03cf7731, 0x93a5c0}}, + {{0x1d59b844, 0x04aba041, 0x16fb7ff1, 0x02c40926, 0x1a5c166a, 0x021ac70a, 0x0bd305aa, 0x12093018, 0x2d440e}}}, + /* 13*16^48*G: */ + {{{0x1e2047ba, 0x130d2b34, 0x0c3d94a8, 0x0e0932d7, 0x07031e54, 0x10700beb, 0x0aeecd76, 0x0522c24e, 0x3fb0b9}}, + {{0x1db24158, 0x1ff66a76, 0x1c0274d5, 0x0415cee2, 0x06dc86c4, 0x110e4cb3, 0x1e5329c9, 0x1cd042fb, 0x9d467a}}}, + /* 15*16^48*G: */ + {{{0x02df71c1, 0x05ededd7, 0x0edc8e80, 0x030d7d5f, 0x1e4381c3, 0x1dd4ef19, 0x0f5741d8, 0x073c11d0, 0xdab094}}, + {{0x04c3a1e3, 0x039a4209, 0x0d138eee, 0x0c661949, 0x00b3d6e9, 0x14379069, 0x13bce16b, 0x03ca89c3, 0x763cbc}}} + }, + { + /* 1*16^49*G: */ + {{{0x0514c6fd, 0x177b17fa, 0x0ac04f9b, 0x10769a1b, 0x15936fd6, 0x0dab887f, 0x1380cf53, 0x1001139e, 0xac25da}}, + {{0x05830541, 0x05a9cbb8, 0x0efcde98, 0x1307d048, 0x1338c810, 0x1498950d, 0x11ee20f6, 0x130b9689, 0xebc69d}}}, + /* 3*16^49*G: */ + {{{0x12fd0e3d, 0x0ca0e3f1, 0x09eb5820, 0x03c9b8a8, 0x05547e63, 0x04338f0b, 0x122ed35d, 0x0d893747, 0xeea7e6}}, + {{0x191d5868, 0x0208fb46, 0x0678f304, 0x175b4460, 0x17d985ac, 0x1f93df4d, 0x0984a210, 0x0b73f112, 0x83fed4}}}, + /* 5*16^49*G: */ + {{{0x0ccb63b3, 0x0cf8a793, 0x10239744, 0x1ffcd888, 0x1c67b7dd, 0x0a59aa01, 0x06f6eb46, 0x1a7d27c4, 0x9a3de2}}, + {{0x1df93fcf, 0x0e2994bb, 0x16089800, 0x003b3fde, 0x13c4c49c, 0x139b7740, 0x0b22027c, 0x120c2222, 0x2f809b}}}, + /* 7*16^49*G: */ + {{{0x163f1117, 0x07651a6e, 0x1fdb62f9, 0x12dee174, 0x1adaf348, 0x0698091f, 0x0b6c1440, 0x1e96a772, 0xa7c382}}, + {{0x1934cb9a, 0x091062f0, 0x1129a330, 0x1d6edda7, 0x1cfb5ae4, 0x1bbbb82e, 0x1e201167, 0x022cec37, 0x1b91e5}}}, + /* 9*16^49*G: */ + {{{0x06774a96, 0x05e40e2d, 0x0e38fa14, 0x063fb230, 0x0f497e82, 0x1dfe41d3, 0x084e1c50, 0x1319b0c2, 0x555aa9}}, + {{0x06db0e34, 0x0a04b96c, 0x189be9a7, 0x1aba9791, 0x0bbb89a0, 0x00f389a8, 0x11a66751, 0x0d1a40f7, 0xb05328}}}, + /* 11*16^49*G: */ + {{{0x0f7dac7d, 0x17bf779d, 0x0904848c, 0x0e572422, 0x1c369165, 0x0bc7c6bb, 0x0b5ed633, 0x0b66914f, 0x1a42f}}, + {{0x0195e46e, 0x1c4a518c, 0x13aa5ac9, 0x15e52651, 0x19216172, 0x1caa5c5f, 0x1e04d25f, 0x070aa40e, 0x957a9c}}}, + /* 13*16^49*G: */ + {{{0x002afc36, 0x015d0ea1, 0x0c1c74f8, 0x1bddaa28, 0x1d3a3134, 0x04f78da2, 0x18f4e96c, 0x06fd60b9, 0x4b47f5}}, + {{0x0f8133ff, 0x144fbb53, 0x17ef68d3, 0x1597d364, 0x1f573345, 0x037d0746, 0x1c30b72c, 0x0073390b, 0xf2fc45}}}, + /* 15*16^49*G: */ + {{{0x17d17f68, 0x15f971e3, 0x02eb61aa, 0x0b43bf97, 0x0418f791, 0x0b7a9b57, 0x033b5594, 0x1398a49d, 0x6b3dec}}, + {{0x09232402, 0x1d73d106, 0x1732da33, 0x0552d54d, 0x15d4747f, 0x00da0b66, 0x07bc1426, 0x06ffbdfb, 0xb86539}}} + }, + { + /* 1*16^50*G: */ + {{{0x0fd20bae, 0x0ea71bd1, 0x0d2a0455, 0x06ace5ab, 0x1343a260, 0x1d090bb6, 0x136409ee, 0x1db8779f, 0x285250}}, + {{0x14e0ab97, 0x0ef22ad2, 0x1bfcc8fe, 0x163459e3, 0x0c1716e9, 0x02568823, 0x1aa0fdca, 0x10de95af, 0x7866c0}}}, + /* 3*16^50*G: */ + {{{0x0636a50b, 0x0443b55d, 0x0dd465b3, 0x1dec2d57, 0x0baf65d2, 0x1d097e3c, 0x1d7160db, 0x0ca8bab4, 0xf1e3c5}}, + {{0x0b3128b6, 0x1bbc8a75, 0x0b5e9bb7, 0x1f4aeda4, 0x1f3136b7, 0x1533fb52, 0x139db1cd, 0x0f4dc3df, 0x12b884}}}, + /* 5*16^50*G: */ + {{{0x0e583340, 0x0bf8990a, 0x0d3cec94, 0x1836d6ba, 0x1228cf45, 0x06d5fd4d, 0x129db61f, 0x13903c26, 0x584d72}}, + {{0x14fb24b9, 0x17b72f4b, 0x05301c1c, 0x0ee14cc9, 0x0affa8f1, 0x1e2c9818, 0x02af34c1, 0x148ac1b0, 0x2fdd80}}}, + /* 7*16^50*G: */ + {{{0x0235809b, 0x1641f6f0, 0x1ae05ce4, 0x0e5be16b, 0x03c453c5, 0x0146e11c, 0x1df478b8, 0x001906fb, 0xbaaeae}}, + {{0x0154fd62, 0x0b0ec52e, 0x14b9f973, 0x18788543, 0x1f299835, 0x183de5a4, 0x0e02d288, 0x1067e649, 0x325788}}}, + /* 9*16^50*G: */ + {{{0x0d612268, 0x10021620, 0x17b405bd, 0x1eb3be14, 0x0b8b906c, 0x0f7d21ca, 0x0c69944e, 0x0c6c1842, 0x6c7e4}}, + {{0x060166a0, 0x05a5b009, 0x0b9c262f, 0x1b14b4f0, 0x053ca238, 0x03ae717a, 0x0335d1ff, 0x0bbee5bb, 0xcb6ad5}}}, + /* 11*16^50*G: */ + {{{0x012fbdc8, 0x0a1d1adc, 0x1038a8ef, 0x1c419545, 0x1a36db89, 0x1663db88, 0x10f96f0b, 0x1bd57acc, 0x64131}}, + {{0x09f99380, 0x09ff984d, 0x1ec08297, 0x15c4d163, 0x17598603, 0x006c9a4a, 0x00a3cace, 0x15865ace, 0x882c7f}}}, + /* 13*16^50*G: */ + {{{0x0bac9f32, 0x0f580032, 0x1a26c19d, 0x104398b2, 0x16400443, 0x00b7f0cd, 0x08de2859, 0x15984eb8, 0x366bb7}}, + {{0x1c85d47d, 0x17872e7d, 0x1c09a290, 0x19ca180f, 0x1cfc01fd, 0x01d5c6b0, 0x1c193c1e, 0x0e10f0b5, 0x7d107b}}}, + /* 15*16^50*G: */ + {{{0x06dd27eb, 0x1e5a9294, 0x0ed588c0, 0x18ab86f6, 0x032ecb98, 0x0871cddf, 0x1001ac9f, 0x04af98e7, 0xb767db}}, + {{0x0f65dac4, 0x0a90d23e, 0x1803b505, 0x0e016890, 0x1d85b64b, 0x05c0b5cc, 0x072d73ab, 0x1864c245, 0xdc1308}}} + }, + { + /* 1*16^51*G: */ + {{{0x1e07e4f1, 0x18f9d151, 0x17099f05, 0x0a28fba1, 0x0890e1fc, 0x15e03f7c, 0x19be0637, 0x00c5da06, 0xc472c1}}, + {{0x06b0daa9, 0x18e341ec, 0x0ad76295, 0x076f63c4, 0x067d885f, 0x15ad426b, 0x03a590ca, 0x00328bee, 0x41820e}}}, + /* 3*16^51*G: */ + {{{0x02f8acb1, 0x1b4a9a55, 0x0fc14fd0, 0x1acaa8c2, 0x0c31eb39, 0x1bd25c76, 0x0f5a1786, 0x0732a8bc, 0x86f88f}}, + {{0x05098a19, 0x05821688, 0x05949c45, 0x14c57dd2, 0x1b1214ee, 0x0bc7dac8, 0x035acdf2, 0x0d34d047, 0x2ccfdd}}}, + /* 5*16^51*G: */ + {{{0x1cadab66, 0x041bbdb7, 0x14d580b6, 0x0d46787b, 0x1f9a0e1c, 0x134b306c, 0x19d1f7dd, 0x03f93291, 0xa2a3be}}, + {{0x0c1aeb12, 0x1a509242, 0x002b497b, 0x1bd14a69, 0x15ee1fb2, 0x1f6ba691, 0x199c1941, 0x1cd6a497, 0xa93bd8}}}, + /* 7*16^51*G: */ + {{{0x007c25bf, 0x04e91099, 0x0b6025ee, 0x178eef7c, 0x080be82f, 0x09233be0, 0x16e4d9f8, 0x1daadcf1, 0x354e7c}}, + {{0x1a864211, 0x091d1cca, 0x082a8854, 0x0ead960b, 0x1e5585fd, 0x0c1252e7, 0x01c39baf, 0x1d377328, 0x629d62}}}, + /* 9*16^51*G: */ + {{{0x15e1dad8, 0x13ec1703, 0x112f4b92, 0x014f0b0d, 0x19f498b8, 0x07b90604, 0x016de6d7, 0x155ebbd0, 0xc751c9}}, + {{0x0e4afc8b, 0x09b59b09, 0x02a300b4, 0x112e1474, 0x1a4ffe6f, 0x00feb6e4, 0x178afad3, 0x06ff8f33, 0xcb9864}}}, + /* 11*16^51*G: */ + {{{0x099d9ba2, 0x1890d908, 0x0aa9d5f4, 0x0cafad2f, 0x19ca80cf, 0x09435a87, 0x0085e2ad, 0x08373a3a, 0xaee9cc}}, + {{0x1ed2ad58, 0x06b0241d, 0x05d2439e, 0x1cd1c4d4, 0x0b1f5312, 0x1dfd8063, 0x0dbdefa5, 0x005b6a54, 0xb72cf3}}}, + /* 13*16^51*G: */ + {{{0x094d208d, 0x1ff84124, 0x1ce46918, 0x1b51fe1f, 0x1f0cefb0, 0x1057958f, 0x1b15affd, 0x08d4f225, 0xd0d3f}}, + {{0x1d45d1b1, 0x117a9fbc, 0x0776aff5, 0x0781a34e, 0x09ff0b21, 0x06d32fc8, 0x05a6c11d, 0x1015c3ee, 0xdc371b}}}, + /* 15*16^51*G: */ + {{{0x19cfd890, 0x17411640, 0x01c45171, 0x0d86e6f8, 0x041e1cb3, 0x0c1c3f2a, 0x14d7d1f3, 0x0d68826e, 0x778d14}}, + {{0x16f057f2, 0x0d43fd3e, 0x1482b2b2, 0x148a911d, 0x0cd3796c, 0x18c6cbc3, 0x0bdca949, 0x02676023, 0x3c85ba}}} + }, + { + /* 1*16^52*G: */ + {{{0x039bb85f, 0x10784e1c, 0x14398b0c, 0x03f60d40, 0x13458010, 0x0164cd6a, 0x0cad55d6, 0x11a2ccc8, 0x55d539}}, + {{0x0fed936f, 0x1fb188c2, 0x0cf6787d, 0x1ad4fe30, 0x0a72ad90, 0x154f475d, 0x18b41671, 0x12093ff1, 0x576e22}}}, + /* 3*16^52*G: */ + {{{0x12ea285a, 0x03f15c90, 0x0e443470, 0x0383cdef, 0x0a7a39f0, 0x02c6eee0, 0x022de160, 0x011029f1, 0x1bb464}}, + {{0x107dc702, 0x006453cc, 0x0bea53b7, 0x05469732, 0x0a4fc1e5, 0x0cdc495a, 0x0496903f, 0x17f5f5c2, 0x8a3016}}}, + /* 5*16^52*G: */ + {{{0x1539785a, 0x08094806, 0x0a5fc051, 0x11a0ed70, 0x07a548c8, 0x1f133c31, 0x053b825c, 0x0e1c05f4, 0x4bc4e}}, + {{0x0a62e3bb, 0x1cc823ae, 0x0c9d70d4, 0x002ee4f4, 0x1fb4f877, 0x10e79f9e, 0x130e97d6, 0x04971969, 0x5729f2}}}, + /* 7*16^52*G: */ + {{{0x0114cfb5, 0x096a5d8f, 0x1569a8c4, 0x0c313547, 0x10876d13, 0x1cf0dbef, 0x05cd61dc, 0x1fb83f10, 0xd3e492}}, + {{0x097f7045, 0x075cd52b, 0x1d53bbef, 0x11e0dc8c, 0x1fea39c8, 0x133b5f8a, 0x122c7fb8, 0x014e7f18, 0x3604a7}}}, + /* 9*16^52*G: */ + {{{0x0c55ddff, 0x1133a5dd, 0x152de1c6, 0x1a367ec9, 0x1c1791da, 0x091887e6, 0x094e2939, 0x0ab0c508, 0xbebfc2}}, + {{0x1ea2f303, 0x0a6d8651, 0x02ea9c1b, 0x15045aca, 0x0576c3cc, 0x08e25bbb, 0x133a28e8, 0x0cb812c0, 0x850de2}}}, + /* 11*16^52*G: */ + {{{0x099ead51, 0x0d7a0f26, 0x164893a4, 0x06a87443, 0x184715da, 0x098e8b03, 0x1580beca, 0x1b8e7a41, 0x36e984}}, + {{0x0e0e5e3e, 0x17dcea13, 0x10a02bf1, 0x177d82e0, 0x12b203ba, 0x0fe4d671, 0x017d2fef, 0x08e437e9, 0x143771}}}, + /* 13*16^52*G: */ + {{{0x03093df0, 0x145bbdd9, 0x1d91935e, 0x1c4902ce, 0x193af785, 0x0a3caa6b, 0x12bbcc54, 0x00087ec0, 0x91b675}}, + {{0x12cc9f14, 0x06f461be, 0x12bd9fd7, 0x0d0bf1f3, 0x01c5d933, 0x1d6d4b71, 0x00351df1, 0x03cb0494, 0x7fedb}}}, + /* 15*16^52*G: */ + {{{0x1b7b8dc4, 0x11b3dc37, 0x06ce1228, 0x09260515, 0x02fac5b3, 0x1f0d01b0, 0x00f9f125, 0x18f43891, 0xc5d9c3}}, + {{0x1b2df0ea, 0x0b24bc68, 0x1f524dbb, 0x11ee5fa3, 0x10af3d0d, 0x01c302e2, 0x1e796023, 0x1c4b9fb6, 0x3e59b9}}} + }, + { + /* 1*16^53*G: */ + {{{0x12513926, 0x116de4e1, 0x1b217b31, 0x0d1281df, 0x03383cc2, 0x1d5925fe, 0x1c9a53fa, 0x08c79410, 0x884286}}, + {{0x0fb8a54d, 0x17214155, 0x16f05683, 0x1d6245d7, 0x01207ce0, 0x06d9b2ec, 0x1569a598, 0x1380385b, 0xf77842}}}, + /* 3*16^53*G: */ + {{{0x0520f1f1, 0x095d60cb, 0x1fdf693b, 0x03693cc8, 0x16f4ad7f, 0x1e8b4667, 0x00675697, 0x06deede1, 0x3bad9d}}, + {{0x1698df4d, 0x10cb8392, 0x0d9c961a, 0x1303449d, 0x00e80499, 0x1d3ecef6, 0x1966f367, 0x1c67c49c, 0x49f99d}}}, + /* 5*16^53*G: */ + {{{0x1185ae66, 0x18f22545, 0x09e0f7c2, 0x182db7df, 0x0118ba6e, 0x0fa9e892, 0x11b59e9f, 0x1635b618, 0xa6b3a4}}, + {{0x0bfbf21b, 0x1f5aa9fc, 0x0c92375e, 0x1e14bbeb, 0x1e8d8bcb, 0x148e6cb4, 0x188c4d86, 0x1aec7112, 0xcb6e8}}}, + /* 7*16^53*G: */ + {{{0x0c630e3a, 0x0b426727, 0x1cfc70aa, 0x00c182ff, 0x110c1f61, 0x11d3ec3f, 0x1293889f, 0x0b4d9222, 0x1f848f}}, + {{0x06ca610a, 0x176cffb4, 0x0d65c92b, 0x0724d7fc, 0x1a4264ba, 0x041e8d4e, 0x058e18a7, 0x0599a0df, 0xa02855}}}, + /* 9*16^53*G: */ + {{{0x041bcd10, 0x0ff79e6e, 0x0d138553, 0x12aaec8b, 0x02eb211b, 0x133be365, 0x0d622c68, 0x097d2938, 0xcfd1e5}}, + {{0x0a62e732, 0x000af5cd, 0x154e596b, 0x1322ba10, 0x12fafacd, 0x08dead82, 0x02ee715d, 0x0bec012b, 0xf4e31f}}}, + /* 11*16^53*G: */ + {{{0x028da5fb, 0x1d30ec91, 0x01c39c93, 0x097ebc55, 0x1291b90e, 0x0af1f3b8, 0x19544b1e, 0x01808d93, 0x4b3e73}}, + {{0x1c169e48, 0x1f8531c5, 0x08d1caef, 0x07423938, 0x0b48c65a, 0x1d03dc70, 0x03a7a032, 0x09b446cc, 0x8c4096}}}, + /* 13*16^53*G: */ + {{{0x1f894780, 0x0748d2c4, 0x06bb176e, 0x139946b1, 0x0d8f737e, 0x1c52a5a1, 0x1f9c7552, 0x1bee8871, 0xafe915}}, + {{0x1511d444, 0x1cb4aa9e, 0x102bd14b, 0x1d17ce75, 0x12e36909, 0x01a1199f, 0x1a1aa52d, 0x0811a408, 0x3caec3}}}, + /* 15*16^53*G: */ + {{{0x1182fa6e, 0x0d18fe5e, 0x00722bfd, 0x0c65bad3, 0x1c9e7c0a, 0x11d1b69a, 0x1215619a, 0x05021ff5, 0xc0548}}, + {{0x061cd145, 0x15e7f55b, 0x1db407db, 0x0cc8b096, 0x1602bf5e, 0x05c4a32e, 0x14cf46aa, 0x195a1e3e, 0x2f9cd2}}} + }, + { + /* 1*16^54*G: */ + {{{0x14441fbb, 0x105aead6, 0x1b44578f, 0x150a414b, 0x125559ea, 0x062af6dc, 0x0751fed8, 0x09c43bc4, 0xb4958c}}, + {{0x0add7118, 0x03f1e4fa, 0x118e1053, 0x13ec265a, 0x0b7e12db, 0x00fde1c6, 0x03bf9701, 0x17f32cc8, 0xfcd6e7}}}, + /* 3*16^54*G: */ + {{{0x171f07f1, 0x176b4261, 0x15c31296, 0x19db6e61, 0x0684b878, 0x105b2303, 0x11348cba, 0x0bcf6408, 0xb3a43f}}, + {{0x001dfda5, 0x1e6917a7, 0x12c3b314, 0x10ef419b, 0x15ee7ec7, 0x1139b4cb, 0x1ae1060c, 0x0b6491fa, 0x34c64f}}}, + /* 5*16^54*G: */ + {{{0x0b559d49, 0x1be4bd23, 0x1726d13f, 0x0368d21b, 0x008b148e, 0x17fec260, 0x052b0998, 0x0d348d7c, 0x452e98}}, + {{0x1a0d6ba7, 0x03e30236, 0x07b9095d, 0x050ad876, 0x1ee52598, 0x02bdb3b0, 0x0343d700, 0x11e32bf0, 0x8c5e8a}}}, + /* 7*16^54*G: */ + {{{0x13ce94da, 0x1bd33f5a, 0x00a79814, 0x049e84ad, 0x074ee8bb, 0x106e1d62, 0x0aed4737, 0x1a918dac, 0x19a7f5}}, + {{0x1025e7bb, 0x182238b1, 0x097ac0dc, 0x04a60d5c, 0x0a2e8fb6, 0x08ea2100, 0x170cbda9, 0x14f5260e, 0xa2504b}}}, + /* 9*16^54*G: */ + {{{0x147dc697, 0x0b4b6636, 0x1856e6ee, 0x1c315f6b, 0x06fa417e, 0x18595afe, 0x1370047a, 0x004149e6, 0xbdaf5b}}, + {{0x06a479e2, 0x088e5f3c, 0x0de91dee, 0x045cf10b, 0x1aa08551, 0x1af23dab, 0x0db233d5, 0x0d97bf50, 0x3cec0c}}}, + /* 11*16^54*G: */ + {{{0x0ce05e10, 0x1005c8db, 0x1841880a, 0x1ef93e87, 0x070db8ae, 0x1bff4267, 0x0576ae12, 0x1d2be73a, 0x265dba}}, + {{0x171324f4, 0x1bf80c58, 0x19319fff, 0x07e7267a, 0x15dcb066, 0x0745ab65, 0x1eb7cecf, 0x1a134606, 0x58df63}}}, + /* 13*16^54*G: */ + {{{0x13fe5938, 0x08ade2ad, 0x0db5f37b, 0x10607b6c, 0x068669ec, 0x04ea9d2b, 0x0e5a27dd, 0x07e2fccc, 0xc43e08}}, + {{0x183732f3, 0x13cbab76, 0x1101d1dd, 0x0460e2c4, 0x0402eab6, 0x0181d5e2, 0x1160d424, 0x12473f79, 0x54c602}}}, + /* 15*16^54*G: */ + {{{0x1dd52975, 0x18e387bc, 0x0d106030, 0x1e1fa60d, 0x066ba2bc, 0x086d3bd9, 0x121996b1, 0x0e0147f0, 0x7868f1}}, + {{0x1c626fac, 0x00b76a81, 0x05a4110c, 0x0df3d94d, 0x1276c68f, 0x10e36d88, 0x1b8444fe, 0x19e6242f, 0xe89097}}} + }, + { + /* 1*16^55*G: */ + {{{0x0e12e1df, 0x0127321b, 0x1d87412b, 0x0ffa16fa, 0x0027cd8a, 0x1f89d9a3, 0x0ad904d2, 0x12d11d26, 0xd0e091}}, + {{0x1fd28fbe, 0x132a26dc, 0x11ae37da, 0x19897b30, 0x1f867544, 0x105b48ed, 0x114ad3ad, 0x0b3fcfa2, 0x69c9a}}}, + /* 3*16^55*G: */ + {{{0x084aa098, 0x186c2880, 0x1b8f80ae, 0x02028152, 0x1fa8509c, 0x1ed65fe0, 0x03ace629, 0x0a942661, 0xb517a4}}, + {{0x0540efbf, 0x0025acfa, 0x0911ff58, 0x0916a8d2, 0x06fa3a4d, 0x1f17d879, 0x1e6983a8, 0x0fa183f0, 0xa3d87}}}, + /* 5*16^55*G: */ + {{{0x0744bfa1, 0x0cad6552, 0x04d90f5b, 0x0da4f9c1, 0x1e387cc2, 0x13896c79, 0x1bd9ef08, 0x07096a2c, 0xf8ec14}}, + {{0x12b65f6d, 0x14927319, 0x04001831, 0x06f58b87, 0x00f610a6, 0x07d934eb, 0x0698c8da, 0x164227f7, 0x761134}}}, + /* 7*16^55*G: */ + {{{0x1227a4bb, 0x1161df49, 0x03667cbd, 0x0d63e01f, 0x0f2e64be, 0x075690ea, 0x0b9e539d, 0x0f1b6f7f, 0x320cff}}, + {{0x10f3d2d4, 0x00e64835, 0x18be5c16, 0x0e46e813, 0x16299604, 0x0b512a7f, 0x1a4aadde, 0x1a80e550, 0xaf9fe8}}}, + /* 9*16^55*G: */ + {{{0x1c2ca683, 0x1adad2f2, 0x0569cdce, 0x19e6bc15, 0x1426a206, 0x0ee65aa1, 0x16145fb7, 0x0f8d4f5d, 0xc08de}}, + {{0x1db5f259, 0x12036dab, 0x1a9a31a4, 0x11af6fc1, 0x00e79c3c, 0x14ce6fe7, 0x1866df20, 0x10abd42d, 0xddb76d}}}, + /* 11*16^55*G: */ + {{{0x052ae5cd, 0x033d67c1, 0x1f75e187, 0x0ca5f5e9, 0x0390995b, 0x1bd22672, 0x10f4639b, 0x0d5a188f, 0xd1f8c7}}, + {{0x1e6d2dda, 0x15cbde1f, 0x027d3f1f, 0x15d02ad3, 0x1203239b, 0x0bd80fb0, 0x000ab1e6, 0x18cc241d, 0x74d45d}}}, + /* 13*16^55*G: */ + {{{0x0bdc603f, 0x1c803355, 0x17ff96ad, 0x1acb9acf, 0x020d8c96, 0x1f63133b, 0x03024f8c, 0x0d27e712, 0xa6cb83}}, + {{0x096befcc, 0x16701f06, 0x1985cd72, 0x1d82d498, 0x10b72fb1, 0x0ded2628, 0x0bf23cb6, 0x1c8c3e79, 0xd823c8}}}, + /* 15*16^55*G: */ + {{{0x02c374b0, 0x0f1d3097, 0x1c36d28a, 0x166b316a, 0x04ef0bf5, 0x04b8a921, 0x0c84dafb, 0x123d4d86, 0x8a6c9c}}, + {{0x178c08bd, 0x1fbe7c6d, 0x03d3560e, 0x0a69e868, 0x132a0461, 0x042ee480, 0x1ebde69e, 0x09ecb9bf, 0xe4bc7f}}} + }, + { + /* 1*16^56*G: */ + {{{0x0895df07, 0x1381f887, 0x01daf61a, 0x0be7f403, 0x08ffefd7, 0x03738670, 0x1fbbad6c, 0x0a84f07b, 0x68f6b8}}, + {{0x18712655, 0x063b7c53, 0x042fdfe4, 0x0527a5e6, 0x05028cf5, 0x0226fed2, 0x139bef20, 0x17525c81, 0xcbe1fe}}}, + /* 3*16^56*G: */ + {{{0x1aa89692, 0x00c7d119, 0x1308c239, 0x1611adf2, 0x0a776713, 0x1320920c, 0x1d37a65b, 0x0e302cd1, 0x3bdfca}}, + {{0x1a510308, 0x1ededa18, 0x18bbc4e4, 0x1818c68b, 0x05333c7d, 0x10a8d76d, 0x1ee12509, 0x0d0aca2c, 0xa721f}}}, + /* 5*16^56*G: */ + {{{0x037ea1d7, 0x1cd91a16, 0x06ab9341, 0x126cb1f1, 0x19e4fb23, 0x02a928c6, 0x0158d4ca, 0x12b6ea42, 0xaca8ac}}, + {{0x1ba973a2, 0x0f7d8824, 0x0e4d7a77, 0x1b7fb882, 0x12189e1e, 0x0625c943, 0x108250c1, 0x0cfbaeb9, 0x7f12c5}}}, + /* 7*16^56*G: */ + {{{0x13245b7f, 0x0d93c0e6, 0x165fefd7, 0x1acd2d20, 0x05311a37, 0x10d7cc6c, 0x103881b0, 0x009b6ccf, 0xfa9047}}, + {{0x0ddf6bef, 0x1c19ef8a, 0x13c751fb, 0x1dd9a4c4, 0x1c189cb9, 0x11f6a078, 0x1a90b5be, 0x06ce9506, 0x1a1c8c}}}, + /* 9*16^56*G: */ + {{{0x17f0953a, 0x10fbc7eb, 0x0550e6ad, 0x122907fe, 0x092a8184, 0x1c70e97d, 0x163359ca, 0x15723eaf, 0x1d431a}}, + {{0x1d68f260, 0x1e2cebb4, 0x1c1f9f05, 0x1c535210, 0x1fae0f48, 0x0641e70a, 0x087af14c, 0x1877e322, 0x8d667}}}, + /* 11*16^56*G: */ + {{{0x05227c70, 0x1188b89b, 0x08fa9c16, 0x17d56667, 0x1c60ff32, 0x19ad9718, 0x04df7692, 0x01ab47c2, 0x6deeea}}, + {{0x0369b9b7, 0x0b6d1c08, 0x0420f6eb, 0x15d83cad, 0x0cc84287, 0x05d7f7b5, 0x19000053, 0x01f8e887, 0xcbb93f}}}, + /* 13*16^56*G: */ + {{{0x0421b54d, 0x1afeaf44, 0x159293fe, 0x1657074a, 0x09dca579, 0x0e95d8fd, 0x036352b2, 0x020c6aaf, 0x28135c}}, + {{0x0ee5d868, 0x0e6784dc, 0x18c4362b, 0x09299923, 0x18c15ef0, 0x0eba083f, 0x18541bea, 0x17c70a37, 0x9ed84a}}}, + /* 15*16^56*G: */ + {{{0x08e4ac10, 0x0bf2ac8f, 0x1892a6a4, 0x0d502559, 0x1b568799, 0x062d04ff, 0x1def5b0f, 0x0ec41620, 0x339a05}}, + {{0x0d1312a0, 0x1b6d4322, 0x07319bbd, 0x13cf11e8, 0x1553e503, 0x06fbc567, 0x11fd0e15, 0x17dbad52, 0xca985f}}} + }, + { + /* 1*16^57*G: */ + {{{0x07ea1f34, 0x1a6d58bb, 0x1ce78374, 0x17a6a808, 0x153d6646, 0x0e8bc9d9, 0x0d9b0ed0, 0x1447a8e9, 0x7f9460}}, + {{0x0d9063ec, 0x05f61656, 0x18d3ff16, 0x1f02a249, 0x16661c6f, 0x195fc783, 0x061da7c7, 0x0ef1f60c, 0xd0d516}}}, + /* 3*16^57*G: */ + {{{0x1dfc0a9d, 0x02dba64d, 0x1ddea837, 0x0846b629, 0x0a2a2de4, 0x11b23570, 0x1808a983, 0x1f098653, 0xdb43e7}}, + {{0x1e9ad713, 0x058849d4, 0x14bc153c, 0x1208e6ad, 0x19fa4883, 0x1640a677, 0x1646e295, 0x1457c6d6, 0xb0168d}}}, + /* 5*16^57*G: */ + {{{0x0283808d, 0x05e58bba, 0x190ea24c, 0x1e0f9c6a, 0x078980f8, 0x0f4890fd, 0x06bae145, 0x103dc1a4, 0xe9af30}}, + {{0x19b39d33, 0x13617c71, 0x04db4665, 0x1724a22a, 0x14971976, 0x132a87f7, 0x098216bc, 0x091388e2, 0xa976c8}}}, + /* 7*16^57*G: */ + {{{0x0d8426df, 0x1497a165, 0x1be28289, 0x0272b49c, 0x083590f4, 0x049c1dfc, 0x0601c0eb, 0x0c65900d, 0x6eb733}}, + {{0x000b4267, 0x1fbacf71, 0x1f86e0cf, 0x05d2f907, 0x08e8d925, 0x05967660, 0x0a680c39, 0x1822e60f, 0x96c56e}}}, + /* 9*16^57*G: */ + {{{0x1a16453d, 0x1e8b6be0, 0x040cf6fd, 0x1d0f7cec, 0x0d0e68b7, 0x0dc8fc5a, 0x1d1785d0, 0x0bc0f3ab, 0xd3979d}}, + {{0x07b6d737, 0x1e5dc18b, 0x1a58693c, 0x1becc514, 0x0456917d, 0x092ba9b9, 0x16e69342, 0x06baf335, 0xc55f93}}}, + /* 11*16^57*G: */ + {{{0x0d326504, 0x150ccd2f, 0x0d480b33, 0x15368c4f, 0x0fc12f65, 0x1dc460d7, 0x08d0b0e0, 0x139cb718, 0x54c392}}, + {{0x1ec9e107, 0x1f808fd3, 0x0299c9a2, 0x0a7b3cc1, 0x0ab4447a, 0x1514248a, 0x1b431226, 0x04ac1d42, 0x469630}}}, + /* 13*16^57*G: */ + {{{0x1b5ecce7, 0x0227abb5, 0x03484d4c, 0x102b1618, 0x059c8732, 0x0741e0cb, 0x1b16e13a, 0x1650ccda, 0x3744e9}}, + {{0x0a247721, 0x00990a0b, 0x09be0e48, 0x116be0a5, 0x1ec3c28e, 0x14ab7594, 0x1ea83839, 0x1f1b3208, 0x9546e0}}}, + /* 15*16^57*G: */ + {{{0x05fef996, 0x064946f2, 0x1094d454, 0x0d1ec728, 0x1f2de140, 0x08520f79, 0x154cc933, 0x02fc6cad, 0x11343e}}, + {{0x1792aded, 0x00a8573a, 0x01bc6390, 0x1c9acb41, 0x13765d0c, 0x0fc98313, 0x1bbac137, 0x101bd751, 0x4a9e84}}} + }, + { + /* 1*16^58*G: */ + {{{0x0e6d8483, 0x164da6bc, 0x059fc373, 0x05af508d, 0x0e94582f, 0x1a4f8db7, 0x18f4a563, 0x0c1467aa, 0x9c39cb}}, + {{0x0b2c50fb, 0x0599ab7b, 0x0f90da25, 0x1bca5e7b, 0x16546bba, 0x0b5bde50, 0x14400f46, 0x03dc927c, 0xf097bf}}}, + /* 3*16^58*G: */ + {{{0x07a14dda, 0x0ae18fc2, 0x12d37cfd, 0x1a0852ce, 0x13083606, 0x147b9200, 0x0b5d10dd, 0x19921d5b, 0x18f37a}}, + {{0x05ac8364, 0x117e6e19, 0x014db2f8, 0x11ef8f15, 0x1cd0b77d, 0x1ff6770d, 0x109b5eef, 0x17554125, 0x2f944b}}}, + /* 5*16^58*G: */ + {{{0x0c7d59be, 0x13a74746, 0x024cbed5, 0x1430b11c, 0x0736b98e, 0x1ff723b9, 0x07693b17, 0x118503cf, 0x541335}}, + {{0x04f80590, 0x0bf50fb7, 0x002cd9cb, 0x04b62b92, 0x0515a53e, 0x07e900b2, 0x00939f12, 0x1bd2d396, 0x680fd4}}}, + /* 7*16^58*G: */ + {{{0x076051a8, 0x15c064fc, 0x115fa963, 0x0ee72c74, 0x05280bed, 0x00d1e0dc, 0x13c1773f, 0x04d23632, 0x4e2fd1}}, + {{0x09cc9005, 0x17f63a7f, 0x113f8b9a, 0x11754b25, 0x031bcebb, 0x1ad0a845, 0x0ec8dc6c, 0x1b7ebe9f, 0x122abb}}}, + /* 9*16^58*G: */ + {{{0x16a80e09, 0x13e547d2, 0x097d7f8d, 0x0be1eecc, 0x08fa0a27, 0x1ab409e0, 0x0d648013, 0x1a97dfe3, 0x2de758}}, + {{0x036a1cd3, 0x0b176faa, 0x16b5b267, 0x15b8cd2b, 0x064a07a1, 0x1958132f, 0x199f5f00, 0x062efb1d, 0xdd9acf}}}, + /* 11*16^58*G: */ + {{{0x1a3628ac, 0x1281ad97, 0x16d593b0, 0x177459be, 0x012a4568, 0x10b9e377, 0x095ca316, 0x159b83a9, 0xf597a0}}, + {{0x0cd3550f, 0x1501886b, 0x04841b9f, 0x1d9f23a8, 0x02cc0772, 0x1db944b1, 0x1155eec6, 0x11c6657a, 0xdb916}}}, + /* 13*16^58*G: */ + {{{0x0b75d6c3, 0x06b41ea5, 0x0e8a159e, 0x14a8afaa, 0x040f3c42, 0x038c10df, 0x1ee42284, 0x10dade89, 0xaa222a}}, + {{0x044cb028, 0x1932d273, 0x0a323d84, 0x03f9296b, 0x0df42607, 0x0512d771, 0x19db3912, 0x12600351, 0x563787}}}, + /* 15*16^58*G: */ + {{{0x035790c9, 0x1d42b9c9, 0x1cf140df, 0x03722ee7, 0x15e2e9e0, 0x0321c979, 0x16dd5bc3, 0x0d79b2e2, 0x8568b2}}, + {{0x06b1f5ac, 0x09faa9c1, 0x0151e7f7, 0x0bcbf1f7, 0x03ce8014, 0x0705721b, 0x0ab7a41e, 0x034b09ba, 0xd3f226}}} + }, + { + /* 1*16^59*G: */ + {{{0x1c38d4e4, 0x0ed4be2a, 0x0c5cdd1f, 0x1acbe363, 0x01e25e2f, 0x173a180c, 0x04e25d59, 0x04c22453, 0x3d9285}}, + {{0x00ccf0d3, 0x1d577806, 0x1eaf1fdb, 0x15627032, 0x069eacc0, 0x0b81ae14, 0x0ad4ffc1, 0x14ba8d1d, 0xd32ca0}}}, + /* 3*16^59*G: */ + {{{0x0dd7718a, 0x039192c0, 0x0f9393b4, 0x1036ca33, 0x0dff891c, 0x0cd12f3b, 0x1f0fdf05, 0x06e57205, 0x3b180e}}, + {{0x1afd82db, 0x1331314c, 0x0b45341c, 0x1222ace0, 0x1211e584, 0x1e4e9482, 0x02abea92, 0x02fe6d6b, 0xf2b6b1}}}, + /* 5*16^59*G: */ + {{{0x13d3653d, 0x140d288c, 0x1919f57e, 0x1d8964e9, 0x03eb2134, 0x07a04c54, 0x127d17bd, 0x00723ad3, 0xf352ff}}, + {{0x0a44f28e, 0x0f333c64, 0x1160b41e, 0x132bf2e5, 0x0d5055c1, 0x0b9efed3, 0x1af4082f, 0x0d996d8b, 0x447262}}}, + /* 7*16^59*G: */ + {{{0x0d4478da, 0x130ef8d7, 0x03805535, 0x19ed8448, 0x13ca1f15, 0x02e6dfbc, 0x108c2bed, 0x0e2069b1, 0x670ee4}}, + {{0x14f563f0, 0x147ff27f, 0x1c91dc18, 0x07702c1f, 0x150e81cc, 0x102d89c3, 0x0b289519, 0x084b7404, 0x5ca0c7}}}, + /* 9*16^59*G: */ + {{{0x03dbd581, 0x02714822, 0x15acd6eb, 0x1d671051, 0x06fa93cf, 0x1d185676, 0x0f6fbeef, 0x0a8693b3, 0x96f2e3}}, + {{0x08f59952, 0x0cd27ff7, 0x13d75153, 0x031e3aa0, 0x1baf435a, 0x0c71cb06, 0x1b3d3f97, 0x0110baa4, 0x9fcd8}}}, + /* 11*16^59*G: */ + {{{0x04e9c2fc, 0x159a1925, 0x0f5c1a87, 0x19e19e5f, 0x09a35e72, 0x01058a30, 0x06b20106, 0x0a2fd073, 0xc4946e}}, + {{0x06398ce8, 0x01a3b1bb, 0x1188c48d, 0x17e71da2, 0x18237e48, 0x07b47a3d, 0x0933a668, 0x041630b1, 0x748901}}}, + /* 13*16^59*G: */ + {{{0x04960b03, 0x05c8b9f4, 0x0023a3d7, 0x18756191, 0x14d8fb6a, 0x0462bc04, 0x0f6fe923, 0x09b537c6, 0x1653b6}}, + {{0x10f73c69, 0x00352a75, 0x0d5939fe, 0x11c1c943, 0x1a8948b3, 0x15ec1f4a, 0x15827d2c, 0x102d3cba, 0xa58370}}}, + /* 15*16^59*G: */ + {{{0x1b63640e, 0x0abbf18d, 0x11cb7cb1, 0x176fe521, 0x1cbf4979, 0x13ce5342, 0x14fd4031, 0x1afda5e2, 0x51076d}}, + {{0x02e4476c, 0x1b4b943c, 0x083bc087, 0x1d49d3ce, 0x0fda6c8b, 0x1280b970, 0x1ddabaf9, 0x0945adbb, 0xb39727}}} + }, + { + /* 1*16^60*G: */ + {{{0x044e8de3, 0x0318258d, 0x130781d8, 0x112cd45d, 0x117915c0, 0x1ee7845e, 0x02dce969, 0x16e8d102, 0xf50b99}}, + {{0x1b7f3588, 0x11f9dd36, 0x1c87a152, 0x0be31a42, 0x1cebbe97, 0x0b9d16f6, 0x1c321e26, 0x03cabe31, 0xe2b506}}}, + /* 3*16^60*G: */ + {{{0x02accf8b, 0x0ee35b5c, 0x005be9f7, 0x05332305, 0x1430481d, 0x1871289c, 0x1dc1917c, 0x0c34aa0a, 0x598d7f}}, + {{0x0f6cb808, 0x1c2339e0, 0x0d502e46, 0x11351e6a, 0x1ebcad22, 0x08b15939, 0x182551b1, 0x1ee9f1e4, 0x9f3121}}}, + /* 5*16^60*G: */ + {{{0x04aa7b3e, 0x1d9cd2a3, 0x1b273aa7, 0x09de360a, 0x0581013c, 0x1048aa0e, 0x113593f4, 0x025e93e9, 0x715a20}}, + {{0x1c7d081d, 0x0d19ca25, 0x02d1f436, 0x178b1151, 0x13b62421, 0x1447c548, 0x10287de4, 0x16354c0d, 0x5922b3}}}, + /* 7*16^60*G: */ + {{{0x020db220, 0x0dedb4bb, 0x01eb3934, 0x1996202d, 0x07876c71, 0x0744bfdc, 0x04971027, 0x0bcd5536, 0x49ec8c}}, + {{0x077338c2, 0x0dc56503, 0x0ee733a6, 0x1860e7ca, 0x15429842, 0x061a432f, 0x0a6cf6a7, 0x09fcbd4c, 0x99a97d}}}, + /* 9*16^60*G: */ + {{{0x1e771268, 0x0f5e518a, 0x02995a14, 0x1e294fb2, 0x07b7a2f4, 0x0c8702f0, 0x1120f9bc, 0x01a90a16, 0x1f8fb7}}, + {{0x0909c8dd, 0x17e98086, 0x04aceac6, 0x1a786239, 0x192a14e1, 0x16ba3930, 0x0afc4b0b, 0x1b68c374, 0xf53e7a}}}, + /* 11*16^60*G: */ + {{{0x08d9819e, 0x0f607959, 0x0b6ac695, 0x0cf25ee8, 0x0732cd60, 0x0a15d33c, 0x187f7574, 0x034c92fe, 0xb8d5c7}}, + {{0x09138ac4, 0x03c5f475, 0x15170f37, 0x093e26c3, 0x1dc79e2f, 0x121acdb1, 0x1e08edbb, 0x1e26426f, 0x1cd14e}}}, + /* 13*16^60*G: */ + {{{0x00bca3f3, 0x149edf33, 0x1801241a, 0x0686a28a, 0x0d8c4ecb, 0x15b0e440, 0x18f7758f, 0x158cb755, 0x2265b5}}, + {{0x117409ff, 0x0c14e362, 0x0e4f5689, 0x014c25a4, 0x164983c8, 0x09d1d884, 0x183d868c, 0x17eb959f, 0x97a198}}}, + /* 15*16^60*G: */ + {{{0x05bac36e, 0x19691ffa, 0x1d77340d, 0x11328b32, 0x1abcb599, 0x054fafe4, 0x049487f6, 0x1a206b09, 0xaf381c}}, + {{0x11b119a9, 0x19ec43d5, 0x1352a43f, 0x1705e3de, 0x02648589, 0x1f914a8d, 0x1ef72515, 0x0ff6fbe1, 0x681a08}}} + }, + { + /* 1*16^61*G: */ + {{{0x0037cfb4, 0x10cca02b, 0x136aa167, 0x01e48d87, 0x0b0e0740, 0x1a4406d0, 0x142c35df, 0x1047febd, 0x42531}}, + {{0x18775d23, 0x05b992f6, 0x1b177500, 0x07c9ea69, 0x01faceea, 0x12686433, 0x1df98a32, 0x199f5c01, 0xc90e8b}}}, + /* 3*16^61*G: */ + {{{0x06c34577, 0x027b39aa, 0x094abdde, 0x013d91cd, 0x0e4bde64, 0x11847460, 0x0922c7d7, 0x141c6179, 0x27557a}}, + {{0x0416193c, 0x0ff5cdc0, 0x110e02eb, 0x0594e6e9, 0x134f318a, 0x0bad24fe, 0x0ceddf23, 0x0b08c20b, 0x8399c7}}}, + /* 5*16^61*G: */ + {{{0x0401f4d3, 0x12c7edb5, 0x056cc07b, 0x185ca1d5, 0x1d7decf6, 0x1c1dfab0, 0x0d923941, 0x02fa4b0e, 0x8e6878}}, + {{0x0294d86b, 0x0140f4a2, 0x08644a24, 0x172de25d, 0x13cae900, 0x04d02836, 0x0fe98be0, 0x110dc593, 0x989cab}}}, + /* 7*16^61*G: */ + {{{0x0d2aa8e6, 0x0cb1ef13, 0x1bff8b71, 0x06b3f881, 0x1dbee205, 0x1401e533, 0x13db440d, 0x08c4a7cb, 0x98a417}}, + {{0x006cf75b, 0x0ba05f6b, 0x1fb4865a, 0x042ff556, 0x1cec9e30, 0x017ad17a, 0x0f5ac455, 0x128fc68c, 0x579ac6}}}, + /* 9*16^61*G: */ + {{{0x152c2d31, 0x0516647b, 0x187bb35f, 0x01576118, 0x1a946180, 0x17221f10, 0x03f64885, 0x084460a8, 0xe16854}}, + {{0x04a50fec, 0x05c41b41, 0x0660e507, 0x0c3257f1, 0x1c9343e7, 0x13216815, 0x0850becb, 0x0b9251ce, 0x70085}}}, + /* 11*16^61*G: */ + {{{0x13a7cdad, 0x119dd71b, 0x02f3ebd2, 0x1b07a5ca, 0x151a53ca, 0x117299c4, 0x0fa8728a, 0x09613aa2, 0xbfa631}}, + {{0x095cb953, 0x0fc44981, 0x1011e871, 0x0321f190, 0x0d1a7261, 0x02ddd8f7, 0x11e0a97e, 0x03299005, 0xb452e8}}}, + /* 13*16^61*G: */ + {{{0x0ade0fb7, 0x0de64280, 0x1946363b, 0x1b8e9bd4, 0x18e200c6, 0x0baf36ec, 0x134fb3c2, 0x05a152c3, 0xe68708}}, + {{0x1d4d6ece, 0x0bcf0798, 0x03089664, 0x03d0bdf1, 0x1a72117c, 0x072990e8, 0x1555797c, 0x090d0992, 0x2135a4}}}, + /* 15*16^61*G: */ + {{{0x0e432daf, 0x01e5af86, 0x009eb272, 0x1db41155, 0x14975f3b, 0x146bca83, 0x07a52ff0, 0x1f0c5535, 0x7ab16e}}, + {{0x071bdc48, 0x08bac455, 0x13f6c04c, 0x139c75ce, 0x1a7c5c7e, 0x0c1f146d, 0x02c68d64, 0x0152f865, 0x584e0e}}} + }, + { + /* 1*16^62*G: */ + {{{0x085fbd44, 0x03a3894c, 0x09899eb0, 0x0595473e, 0x1222c89c, 0x18e70b6a, 0x04178151, 0x1b5b356b, 0x9bbf06}}, + {{0x1a1d3e88, 0x1a23efd3, 0x00dbb4a8, 0x097bb82a, 0x147e8c0d, 0x0d798537, 0x028d9d57, 0x1509bc24, 0x1bcc7f}}}, + /* 3*16^62*G: */ + {{{0x14a7b506, 0x1bd73c95, 0x0182f822, 0x0b1775cf, 0x00ee9227, 0x1d9573a8, 0x0f4d0a73, 0x1ecb676b, 0x646ff7}}, + {{0x0b36f946, 0x0bce0929, 0x039a6572, 0x1bf89f81, 0x08fe8492, 0x1198c025, 0x02956987, 0x13a0c943, 0xbc112a}}}, + /* 5*16^62*G: */ + {{{0x0103b553, 0x0a5b8e4e, 0x0e16a005, 0x01d44f06, 0x0507ebe6, 0x0800593f, 0x0e6a7430, 0x0f54c2fa, 0x7cc054}}, + {{0x0d45a526, 0x1cce5d1e, 0x08a2df55, 0x10b41558, 0x094c4001, 0x14659cfe, 0x116af75c, 0x17a46500, 0x7b329e}}}, + /* 7*16^62*G: */ + {{{0x19e717a4, 0x0177a2a0, 0x1c06e06b, 0x1457b559, 0x0e15468d, 0x16a9b6d7, 0x0d38158f, 0x1321783b, 0x946851}}, + {{0x1526dea3, 0x1af87e8d, 0x02b36729, 0x132b21ee, 0x07dc0579, 0x08735933, 0x06a2cee3, 0x0841b8b2, 0xca5c78}}}, + /* 9*16^62*G: */ + {{{0x08362735, 0x1c161b78, 0x0acc9ef7, 0x1166fde2, 0x0d1f5dff, 0x07c75229, 0x03eac496, 0x037cfc1d, 0xe1b98f}}, + {{0x0ecb11b7, 0x0b09c64e, 0x1d0242be, 0x13dc67be, 0x12ba27e1, 0x1a4d41dd, 0x082df816, 0x15b352ed, 0xca83e9}}}, + /* 11*16^62*G: */ + {{{0x19046346, 0x1a05dec1, 0x0510020e, 0x0b1bce60, 0x1962d56a, 0x1035ecb3, 0x1fbdb422, 0x0b91fac0, 0x3536f2}}, + {{0x0c14fea6, 0x0008315e, 0x166cf8a5, 0x187a3d45, 0x1e1c39e6, 0x0b50d294, 0x0279cee8, 0x1c2fbc6a, 0x1e271f}}}, + /* 13*16^62*G: */ + {{{0x0847f6f8, 0x1ffc1f6b, 0x103bd4c3, 0x136a3f7a, 0x18c3c102, 0x08f9a5bf, 0x1379a405, 0x08d7c47a, 0xdf502}}, + {{0x1b1633a6, 0x06654535, 0x17cd126d, 0x1c2ccd13, 0x174ab4c6, 0x1627de10, 0x0728ac8c, 0x0fe53b5e, 0x210704}}}, + /* 15*16^62*G: */ + {{{0x1d4f1b81, 0x02e7576f, 0x1d2ec546, 0x134f4919, 0x09330ad6, 0x11d99b29, 0x0e63da77, 0x1a899ea6, 0xca9dd5}}, + {{0x02b7c8bd, 0x06316572, 0x0b6843e3, 0x12ec17f5, 0x07b3e66c, 0x18fda223, 0x11590091, 0x10ca37c5, 0x6e4b98}}} + }, + { + /* 1*16^63*G: */ + {{{0x044c0448, 0x1569919a, 0x00c678c7, 0x0aed0d82, 0x093e7963, 0x1e659dbc, 0x1e95250f, 0x1ea5287b, 0xb12fad}}, + {{0x1369de57, 0x12baf3b5, 0x1f137ca5, 0x0bce0665, 0x0a6a71d0, 0x07b33bd9, 0x12b3a5be, 0x12b3361e, 0x2e245}}}, + /* 3*16^63*G: */ + {{{0x04e9151f, 0x09b622a3, 0x0361063d, 0x14673390, 0x0fb3e67e, 0x0eed48ec, 0x15a10c95, 0x069e38a0, 0x48388e}}, + {{0x0d7a9434, 0x1f724f6e, 0x17a0c406, 0x028222a7, 0x02bcc99b, 0x19c98aa4, 0x1a79a894, 0x157e9c89, 0xb0ec63}}}, + /* 5*16^63*G: */ + {{{0x0e5b833d, 0x1efda52c, 0x02c90675, 0x1400e794, 0x109c9593, 0x0fc08280, 0x0f697997, 0x08f5c28a, 0xde8e64}}, + {{0x014c5cc7, 0x07e60cd5, 0x0071b27c, 0x1c062652, 0x1e265987, 0x14465eb6, 0x0f638cc8, 0x0782a122, 0x5e146}}}, + /* 7*16^63*G: */ + {{{0x01f7df48, 0x112c9f56, 0x1c4c5ecf, 0x0e8e7d70, 0x0f385b26, 0x0da7272c, 0x1a7a3955, 0x1a149d8f, 0xb18b12}}, + {{0x0846b546, 0x0d9eac87, 0x14795664, 0x07efc907, 0x0c33b3c8, 0x0135e2d6, 0x0d1173b1, 0x04546b3f, 0xff5319}}}, + /* 9*16^63*G: */ + {{{0x19c9fd24, 0x129d6e34, 0x0847837c, 0x1bb1308a, 0x0694402c, 0x05526394, 0x10cf1f07, 0x0e391b92, 0x5f51ad}}, + {{0x0d2ffd3a, 0x01dd7443, 0x092a65a7, 0x03ec488c, 0x04d03872, 0x02fde617, 0x0528334c, 0x023befce, 0x2bbbef}}}, + /* 11*16^63*G: */ + {{{0x17cec42e, 0x1e2031fe, 0x18ef6df8, 0x1b9267dd, 0x0d8556f3, 0x117721a3, 0x1aefe960, 0x1b26e603, 0xfdf340}}, + {{0x0db6908b, 0x07b1a5be, 0x178c320e, 0x1cd57ea1, 0x0d2c4456, 0x0ff39c65, 0x1b875c30, 0x0c72d198, 0xa3e59a}}}, + /* 13*16^63*G: */ + {{{0x01dc4fe8, 0x00c4a2a7, 0x01c9057f, 0x1142752c, 0x1c983f9e, 0x0948bdbe, 0x15e7b191, 0x19173d4b, 0xe3caeb}}, + {{0x1307b403, 0x15b05b90, 0x13e1a845, 0x0006cb42, 0x1f976513, 0x1ae5c580, 0x04a34880, 0x1a4f7e0b, 0x97f093}}}, + /* 15*16^63*G: */ + {{{0x1c119eff, 0x00a6b2e9, 0x07e6e119, 0x005c1815, 0x1a003399, 0x0d2e72c7, 0x16e26bd0, 0x1728550c, 0x3312d}}, + {{0x18b1b950, 0x14ad1d4f, 0x1455617f, 0x18b3b6be, 0x1e86f0ae, 0x1518bc04, 0x137c413b, 0x0c8d66e4, 0x6e3eda}}} + }, diff --git a/applications/external/flipbip/lib/crypto/options.h b/applications/external/flipbip/lib/crypto/options.h new file mode 100644 index 000000000..f0edcc60f --- /dev/null +++ b/applications/external/flipbip/lib/crypto/options.h @@ -0,0 +1,94 @@ +/** + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __OPTIONS_H__ +#define __OPTIONS_H__ + +// use precomputed Curve Points (some scalar multiples of curve base point G) +#ifndef USE_PRECOMPUTED_CP +#define USE_PRECOMPUTED_CP 0 +#endif + +// use fast inverse method +#ifndef USE_INVERSE_FAST +#define USE_INVERSE_FAST 1 +#endif + +// support for printing bignum256 structures via printf +#ifndef USE_BN_PRINT +#define USE_BN_PRINT 0 +#endif + +// use deterministic signatures +#ifndef USE_RFC6979 +#define USE_RFC6979 1 +#endif + +// implement BIP32 caching +#ifndef USE_BIP32_CACHE +#define USE_BIP32_CACHE 0 +#define BIP32_CACHE_SIZE 10 +#define BIP32_CACHE_MAXDEPTH 8 +#endif + +// support constructing BIP32 nodes from ed25519 and curve25519 curves. +#ifndef USE_BIP32_25519_CURVES +#define USE_BIP32_25519_CURVES 0 +#endif + +// implement BIP39 caching +#ifndef USE_BIP39_CACHE +#define USE_BIP39_CACHE 0 +#define BIP39_CACHE_SIZE 4 +#endif + +// support Ethereum operations +#ifndef USE_ETHEREUM +#define USE_ETHEREUM 1 +#endif + +// support NEM operations +#ifndef USE_NEM +#define USE_NEM 0 +#endif + +// support MONERO operations +#ifndef USE_MONERO +#define USE_MONERO 0 +#endif + +// support CARDANO operations +#ifndef USE_CARDANO +#define USE_CARDANO 0 +#endif + +// support Keccak hashing +#ifndef USE_KECCAK +#define USE_KECCAK 1 +#endif + +// add way how to mark confidential data +#ifndef CONFIDENTIAL +#define CONFIDENTIAL +#endif + +#endif diff --git a/applications/external/flipbip/lib/crypto/pbkdf2.c b/applications/external/flipbip/lib/crypto/pbkdf2.c new file mode 100644 index 000000000..e3ebe515e --- /dev/null +++ b/applications/external/flipbip/lib/crypto/pbkdf2.c @@ -0,0 +1,195 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "pbkdf2.h" +#include +#include "hmac.h" +#include "memzero.h" +#include "sha2.h" + +void pbkdf2_hmac_sha256_Init( + PBKDF2_HMAC_SHA256_CTX* pctx, + const uint8_t* pass, + int passlen, + const uint8_t* salt, + int saltlen, + uint32_t blocknr) { + SHA256_CTX ctx = {0}; +#if BYTE_ORDER == LITTLE_ENDIAN + REVERSE32(blocknr, blocknr); +#endif + + hmac_sha256_prepare(pass, passlen, pctx->odig, pctx->idig); + memzero(pctx->g, sizeof(pctx->g)); + pctx->g[8] = 0x80000000; + pctx->g[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH) * 8; + + memcpy(ctx.state, pctx->idig, sizeof(pctx->idig)); + ctx.bitcount = SHA256_BLOCK_LENGTH * 8; + sha256_Update(&ctx, salt, saltlen); + sha256_Update(&ctx, (uint8_t*)&blocknr, sizeof(blocknr)); + sha256_Final(&ctx, (uint8_t*)pctx->g); +#if BYTE_ORDER == LITTLE_ENDIAN + for(uint32_t k = 0; k < SHA256_DIGEST_LENGTH / sizeof(uint32_t); k++) { + REVERSE32(pctx->g[k], pctx->g[k]); + } +#endif + sha256_Transform(pctx->odig, pctx->g, pctx->g); + memcpy(pctx->f, pctx->g, SHA256_DIGEST_LENGTH); + pctx->first = 1; +} + +void pbkdf2_hmac_sha256_Update(PBKDF2_HMAC_SHA256_CTX* pctx, uint32_t iterations) { + for(uint32_t i = pctx->first; i < iterations; i++) { + sha256_Transform(pctx->idig, pctx->g, pctx->g); + sha256_Transform(pctx->odig, pctx->g, pctx->g); + for(uint32_t j = 0; j < SHA256_DIGEST_LENGTH / sizeof(uint32_t); j++) { + pctx->f[j] ^= pctx->g[j]; + } + } + pctx->first = 0; +} + +void pbkdf2_hmac_sha256_Final(PBKDF2_HMAC_SHA256_CTX* pctx, uint8_t* key) { +#if BYTE_ORDER == LITTLE_ENDIAN + for(uint32_t k = 0; k < SHA256_DIGEST_LENGTH / sizeof(uint32_t); k++) { + REVERSE32(pctx->f[k], pctx->f[k]); + } +#endif + memcpy(key, pctx->f, SHA256_DIGEST_LENGTH); + memzero(pctx, sizeof(PBKDF2_HMAC_SHA256_CTX)); +} + +void pbkdf2_hmac_sha256( + const uint8_t* pass, + int passlen, + const uint8_t* salt, + int saltlen, + uint32_t iterations, + uint8_t* key, + int keylen) { + uint32_t last_block_size = keylen % SHA256_DIGEST_LENGTH; + uint32_t blocks_count = keylen / SHA256_DIGEST_LENGTH; + if(last_block_size) { + blocks_count++; + } else { + last_block_size = SHA256_DIGEST_LENGTH; + } + for(uint32_t blocknr = 1; blocknr <= blocks_count; blocknr++) { + PBKDF2_HMAC_SHA256_CTX pctx = {0}; + pbkdf2_hmac_sha256_Init(&pctx, pass, passlen, salt, saltlen, blocknr); + pbkdf2_hmac_sha256_Update(&pctx, iterations); + uint8_t digest[SHA256_DIGEST_LENGTH] = {0}; + pbkdf2_hmac_sha256_Final(&pctx, digest); + uint32_t key_offset = (blocknr - 1) * SHA256_DIGEST_LENGTH; + if(blocknr < blocks_count) { + memcpy(key + key_offset, digest, SHA256_DIGEST_LENGTH); + } else { + memcpy(key + key_offset, digest, last_block_size); + } + } +} + +void pbkdf2_hmac_sha512_Init( + PBKDF2_HMAC_SHA512_CTX* pctx, + const uint8_t* pass, + int passlen, + const uint8_t* salt, + int saltlen, + uint32_t blocknr) { + SHA512_CTX ctx = {0}; +#if BYTE_ORDER == LITTLE_ENDIAN + REVERSE32(blocknr, blocknr); +#endif + + hmac_sha512_prepare(pass, passlen, pctx->odig, pctx->idig); + memzero(pctx->g, sizeof(pctx->g)); + pctx->g[8] = 0x8000000000000000; + pctx->g[15] = (SHA512_BLOCK_LENGTH + SHA512_DIGEST_LENGTH) * 8; + + memcpy(ctx.state, pctx->idig, sizeof(pctx->idig)); + ctx.bitcount[0] = SHA512_BLOCK_LENGTH * 8; + ctx.bitcount[1] = 0; + sha512_Update(&ctx, salt, saltlen); + sha512_Update(&ctx, (uint8_t*)&blocknr, sizeof(blocknr)); + sha512_Final(&ctx, (uint8_t*)pctx->g); +#if BYTE_ORDER == LITTLE_ENDIAN + for(uint32_t k = 0; k < SHA512_DIGEST_LENGTH / sizeof(uint64_t); k++) { + REVERSE64(pctx->g[k], pctx->g[k]); + } +#endif + sha512_Transform(pctx->odig, pctx->g, pctx->g); + memcpy(pctx->f, pctx->g, SHA512_DIGEST_LENGTH); + pctx->first = 1; +} + +void pbkdf2_hmac_sha512_Update(PBKDF2_HMAC_SHA512_CTX* pctx, uint32_t iterations) { + for(uint32_t i = pctx->first; i < iterations; i++) { + sha512_Transform(pctx->idig, pctx->g, pctx->g); + sha512_Transform(pctx->odig, pctx->g, pctx->g); + for(uint32_t j = 0; j < SHA512_DIGEST_LENGTH / sizeof(uint64_t); j++) { + pctx->f[j] ^= pctx->g[j]; + } + } + pctx->first = 0; +} + +void pbkdf2_hmac_sha512_Final(PBKDF2_HMAC_SHA512_CTX* pctx, uint8_t* key) { +#if BYTE_ORDER == LITTLE_ENDIAN + for(uint32_t k = 0; k < SHA512_DIGEST_LENGTH / sizeof(uint64_t); k++) { + REVERSE64(pctx->f[k], pctx->f[k]); + } +#endif + memcpy(key, pctx->f, SHA512_DIGEST_LENGTH); + memzero(pctx, sizeof(PBKDF2_HMAC_SHA512_CTX)); +} + +void pbkdf2_hmac_sha512( + const uint8_t* pass, + int passlen, + const uint8_t* salt, + int saltlen, + uint32_t iterations, + uint8_t* key, + int keylen) { + uint32_t last_block_size = keylen % SHA512_DIGEST_LENGTH; + uint32_t blocks_count = keylen / SHA512_DIGEST_LENGTH; + if(last_block_size) { + blocks_count++; + } else { + last_block_size = SHA512_DIGEST_LENGTH; + } + for(uint32_t blocknr = 1; blocknr <= blocks_count; blocknr++) { + PBKDF2_HMAC_SHA512_CTX pctx = {0}; + pbkdf2_hmac_sha512_Init(&pctx, pass, passlen, salt, saltlen, blocknr); + pbkdf2_hmac_sha512_Update(&pctx, iterations); + uint8_t digest[SHA512_DIGEST_LENGTH] = {0}; + pbkdf2_hmac_sha512_Final(&pctx, digest); + uint32_t key_offset = (blocknr - 1) * SHA512_DIGEST_LENGTH; + if(blocknr < blocks_count) { + memcpy(key + key_offset, digest, SHA512_DIGEST_LENGTH); + } else { + memcpy(key + key_offset, digest, last_block_size); + } + } +} diff --git a/applications/external/flipbip/lib/crypto/pbkdf2.h b/applications/external/flipbip/lib/crypto/pbkdf2.h new file mode 100644 index 000000000..22b580ff4 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/pbkdf2.h @@ -0,0 +1,82 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __PBKDF2_H__ +#define __PBKDF2_H__ + +#include +#include "sha2.h" + +typedef struct _PBKDF2_HMAC_SHA256_CTX { + uint32_t odig[SHA256_DIGEST_LENGTH / sizeof(uint32_t)]; + uint32_t idig[SHA256_DIGEST_LENGTH / sizeof(uint32_t)]; + uint32_t f[SHA256_DIGEST_LENGTH / sizeof(uint32_t)]; + uint32_t g[SHA256_BLOCK_LENGTH / sizeof(uint32_t)]; + char first; +} PBKDF2_HMAC_SHA256_CTX; + +typedef struct _PBKDF2_HMAC_SHA512_CTX { + uint64_t odig[SHA512_DIGEST_LENGTH / sizeof(uint64_t)]; + uint64_t idig[SHA512_DIGEST_LENGTH / sizeof(uint64_t)]; + uint64_t f[SHA512_DIGEST_LENGTH / sizeof(uint64_t)]; + uint64_t g[SHA512_BLOCK_LENGTH / sizeof(uint64_t)]; + char first; +} PBKDF2_HMAC_SHA512_CTX; + +void pbkdf2_hmac_sha256_Init( + PBKDF2_HMAC_SHA256_CTX* pctx, + const uint8_t* pass, + int passlen, + const uint8_t* salt, + int saltlen, + uint32_t blocknr); +void pbkdf2_hmac_sha256_Update(PBKDF2_HMAC_SHA256_CTX* pctx, uint32_t iterations); +void pbkdf2_hmac_sha256_Final(PBKDF2_HMAC_SHA256_CTX* pctx, uint8_t* key); +void pbkdf2_hmac_sha256( + const uint8_t* pass, + int passlen, + const uint8_t* salt, + int saltlen, + uint32_t iterations, + uint8_t* key, + int keylen); + +void pbkdf2_hmac_sha512_Init( + PBKDF2_HMAC_SHA512_CTX* pctx, + const uint8_t* pass, + int passlen, + const uint8_t* salt, + int saltlen, + uint32_t blocknr); +void pbkdf2_hmac_sha512_Update(PBKDF2_HMAC_SHA512_CTX* pctx, uint32_t iterations); +void pbkdf2_hmac_sha512_Final(PBKDF2_HMAC_SHA512_CTX* pctx, uint8_t* key); +void pbkdf2_hmac_sha512( + const uint8_t* pass, + int passlen, + const uint8_t* salt, + int saltlen, + uint32_t iterations, + uint8_t* key, + int keylen); + +#endif diff --git a/applications/external/flipbip/lib/crypto/rand.c b/applications/external/flipbip/lib/crypto/rand.c new file mode 100644 index 000000000..b35214285 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/rand.c @@ -0,0 +1,102 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +// NOTE: +// random32() and random_buffer() have been replaced in this implementation +// with Flipper Zero specific code. The original code is commented out below. + +#include "rand.h" + +// Flipper Zero RNG code: +#include + +#ifndef RAND_PLATFORM_INDEPENDENT + +// Original code: +// #pragma message("NOT SUITABLE FOR PRODUCTION USE! Replace random32() function with your own secure code.") + +// The following code is not supposed to be used in a production environment. +// It's included only to make the library testable. +// The message above tries to prevent any accidental use outside of the test +// environment. +// +// You are supposed to replace the random8() and random32() function with your +// own secure code. There is also a possibility to replace the random_buffer() +// function as it is defined as a weak symbol. + +static uint32_t seed = 0; + +void random_reseed(const uint32_t value) { + seed = value; +} + +// Original code: +// uint32_t random32(void) { +// // Linear congruential generator from Numerical Recipes +// // https://en.wikipedia.org/wiki/Linear_congruential_generator +// seed = 1664525 * seed + 1013904223; +// return seed; +// } + +// Flipper Zero RNG code: +uint32_t random32(void) { + return furi_hal_random_get(); +} + +// Flipper Zero RNG code: +void random_buffer(uint8_t* buf, size_t len) { + furi_hal_random_fill_buf(buf, len); +} + +#endif /* RAND_PLATFORM_INDEPENDENT */ + +// +// The following code is platform independent +// + +// Original code: +// void __attribute__((weak)) random_buffer(uint8_t *buf, size_t len) { +// uint32_t r = 0; +// for (size_t i = 0; i < len; i++) { +// if (i % 4 == 0) { +// r = random32(); +// } +// buf[i] = (r >> ((i % 4) * 8)) & 0xFF; +// } +// } + +uint32_t random_uniform(uint32_t n) { + uint32_t x = 0, max = 0xFFFFFFFF - (0xFFFFFFFF % n); + while((x = random32()) >= max) + ; + return x / (max / n); +} + +void random_permute(char* str, size_t len) { + for(int i = len - 1; i >= 1; i--) { + int j = random_uniform(i + 1); + char t = str[j]; + str[j] = str[i]; + str[i] = t; + } +} diff --git a/applications/external/flipbip/lib/crypto/rand.h b/applications/external/flipbip/lib/crypto/rand.h new file mode 100644 index 000000000..fa854890f --- /dev/null +++ b/applications/external/flipbip/lib/crypto/rand.h @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __RAND_H__ +#define __RAND_H__ + +#include +#include + +void random_reseed(const uint32_t value); +uint32_t random32(void); +void random_buffer(uint8_t* buf, size_t len); + +uint32_t random_uniform(uint32_t n); +void random_permute(char* buf, size_t len); + +#endif diff --git a/applications/external/flipbip/lib/crypto/rc4.c b/applications/external/flipbip/lib/crypto/rc4.c new file mode 100644 index 000000000..b42ad24ed --- /dev/null +++ b/applications/external/flipbip/lib/crypto/rc4.c @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2017 Saleem Rashid + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, E1PRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "rc4.h" + +static inline void rc4_swap(RC4_CTX* ctx, uint8_t i, uint8_t j) { + uint8_t temp = ctx->S[i]; + ctx->S[i] = ctx->S[j]; + ctx->S[j] = temp; +} + +void rc4_init(RC4_CTX* ctx, const uint8_t* key, size_t length) { + ctx->i = 0; + ctx->j = 0; + + for(size_t i = 0; i < 256; i++) { + ctx->S[i] = i; + } + + uint8_t j = 0; + for(size_t i = 0; i < 256; i++) { + j += ctx->S[i] + key[i % length]; + rc4_swap(ctx, i, j); + } +} + +void rc4_encrypt(RC4_CTX* ctx, uint8_t* buffer, size_t length) { + for(size_t idx = 0; idx < length; idx++) { + ctx->i++; + ctx->j += ctx->S[ctx->i]; + + rc4_swap(ctx, ctx->i, ctx->j); + + uint8_t K = ctx->S[(ctx->S[ctx->i] + ctx->S[ctx->j]) % 256]; + buffer[idx] ^= K; + } +} diff --git a/applications/external/flipbip/lib/crypto/rc4.h b/applications/external/flipbip/lib/crypto/rc4.h new file mode 100644 index 000000000..860d33130 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/rc4.h @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2017 Saleem Rashid + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __RC4_H__ +#define __RC4_H__ + +#include +#include + +typedef struct { + uint8_t S[256]; + uint8_t i, j; +} RC4_CTX; + +void rc4_init(RC4_CTX* ctx, const uint8_t* key, size_t length); +void rc4_encrypt(RC4_CTX* ctx, uint8_t* buffer, size_t length); + +#endif diff --git a/applications/external/flipbip/lib/crypto/rfc6979.c b/applications/external/flipbip/lib/crypto/rfc6979.c new file mode 100644 index 000000000..6bede6f5c --- /dev/null +++ b/applications/external/flipbip/lib/crypto/rfc6979.c @@ -0,0 +1,65 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * Copyright (c) 2015 Jochen Hoenicke + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +#include + +#include "hmac_drbg.h" +#include "memzero.h" +#include "rfc6979.h" + +void init_rfc6979( + const uint8_t* priv_key, + const uint8_t* hash, + const ecdsa_curve* curve, + rfc6979_state* state) { + if(curve) { + bignum256 hash_bn = {0}; + bn_read_be(hash, &hash_bn); + + // Make sure hash is partly reduced modulo order + assert(bn_bitcount(&curve->order) >= 256); + bn_mod(&hash_bn, &curve->order); + + uint8_t hash_reduced[32] = {0}; + bn_write_be(&hash_bn, hash_reduced); + memzero(&hash_bn, sizeof(hash_bn)); + hmac_drbg_init(state, priv_key, 32, hash_reduced, 32); + memzero(hash_reduced, sizeof(hash_reduced)); + } else { + hmac_drbg_init(state, priv_key, 32, hash, 32); + } +} + +// generate next number from deterministic random number generator +void generate_rfc6979(uint8_t rnd[32], rfc6979_state* state) { + hmac_drbg_generate(state, rnd, 32); +} + +// generate K in a deterministic way, according to RFC6979 +// http://tools.ietf.org/html/rfc6979 +void generate_k_rfc6979(bignum256* k, rfc6979_state* state) { + uint8_t buf[32] = {0}; + generate_rfc6979(buf, state); + bn_read_be(buf, k); + memzero(buf, sizeof(buf)); +} diff --git a/applications/external/flipbip/lib/crypto/rfc6979.h b/applications/external/flipbip/lib/crypto/rfc6979.h new file mode 100644 index 000000000..02367c38e --- /dev/null +++ b/applications/external/flipbip/lib/crypto/rfc6979.h @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * Copyright (c) 2015-2017 Jochen Hoenicke + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __RFC6979_H__ +#define __RFC6979_H__ + +#include +#include "bignum.h" +#include "ecdsa.h" +#include "hmac_drbg.h" + +// rfc6979 pseudo random number generator state +typedef HMAC_DRBG_CTX rfc6979_state; + +void init_rfc6979( + const uint8_t* priv_key, + const uint8_t* hash, + const ecdsa_curve* curve, + rfc6979_state* rng); +void generate_rfc6979(uint8_t rnd[32], rfc6979_state* rng); +void generate_k_rfc6979(bignum256* k, rfc6979_state* rng); + +#endif diff --git a/applications/external/flipbip/lib/crypto/ripemd160.c b/applications/external/flipbip/lib/crypto/ripemd160.c new file mode 100644 index 000000000..7d7f3898b --- /dev/null +++ b/applications/external/flipbip/lib/crypto/ripemd160.c @@ -0,0 +1,330 @@ +/* + * RIPE MD-160 implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * The RIPEMD-160 algorithm was designed by RIPE in 1996 + * http://homes.esat.kuleuven.be/~bosselae/ripemd160.html + * http://ehash.iaik.tugraz.at/wiki/RIPEMD-160 + */ + +#include + +#include "ripemd160.h" +#include "memzero.h" + +/* + * 32-bit integer manipulation macros (little endian) + */ +#ifndef GET_UINT32_LE +#define GET_UINT32_LE(n, b, i) \ + { \ + (n) = ((uint32_t)(b)[(i)]) | ((uint32_t)(b)[(i) + 1] << 8) | \ + ((uint32_t)(b)[(i) + 2] << 16) | ((uint32_t)(b)[(i) + 3] << 24); \ + } +#endif + +#ifndef PUT_UINT32_LE +#define PUT_UINT32_LE(n, b, i) \ + { \ + (b)[(i)] = (uint8_t)(((n)) & 0xFF); \ + (b)[(i) + 1] = (uint8_t)(((n) >> 8) & 0xFF); \ + (b)[(i) + 2] = (uint8_t)(((n) >> 16) & 0xFF); \ + (b)[(i) + 3] = (uint8_t)(((n) >> 24) & 0xFF); \ + } +#endif + +/* + * RIPEMD-160 context setup + */ +void ripemd160_Init(RIPEMD160_CTX* ctx) { + memzero(ctx, sizeof(RIPEMD160_CTX)); + ctx->total[0] = 0; + ctx->total[1] = 0; + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xC3D2E1F0; +} + +#if !defined(MBEDTLS_RIPEMD160_PROCESS_ALT) +/* + * Process one block + */ +void ripemd160_process(RIPEMD160_CTX* ctx, const uint8_t data[RIPEMD160_BLOCK_LENGTH]) { + uint32_t A = 0, B = 0, C = 0, D = 0, E = 0, Ap = 0, Bp = 0, Cp = 0, Dp = 0, Ep = 0, + X[16] = {0}; + + GET_UINT32_LE(X[0], data, 0); + GET_UINT32_LE(X[1], data, 4); + GET_UINT32_LE(X[2], data, 8); + GET_UINT32_LE(X[3], data, 12); + GET_UINT32_LE(X[4], data, 16); + GET_UINT32_LE(X[5], data, 20); + GET_UINT32_LE(X[6], data, 24); + GET_UINT32_LE(X[7], data, 28); + GET_UINT32_LE(X[8], data, 32); + GET_UINT32_LE(X[9], data, 36); + GET_UINT32_LE(X[10], data, 40); + GET_UINT32_LE(X[11], data, 44); + GET_UINT32_LE(X[12], data, 48); + GET_UINT32_LE(X[13], data, 52); + GET_UINT32_LE(X[14], data, 56); + GET_UINT32_LE(X[15], data, 60); + + A = Ap = ctx->state[0]; + B = Bp = ctx->state[1]; + C = Cp = ctx->state[2]; + D = Dp = ctx->state[3]; + E = Ep = ctx->state[4]; + +#define F1(x, y, z) (x ^ y ^ z) +#define F2(x, y, z) ((x & y) | (~x & z)) +#define F3(x, y, z) ((x | ~y) ^ z) +#define F4(x, y, z) ((x & z) | (y & ~z)) +#define F5(x, y, z) (x ^ (y | ~z)) + +#define S(x, n) ((x << n) | (x >> (32 - n))) + +#define P(a, b, c, d, e, r, s, f, k) \ + a += f(b, c, d) + X[r] + k; \ + a = S(a, s) + e; \ + c = S(c, 10); + +#define P2(a, b, c, d, e, r, s, rp, sp) \ + P(a, b, c, d, e, r, s, F, K); \ + P(a##p, b##p, c##p, d##p, e##p, rp, sp, Fp, Kp); + +#define F F1 +#define K 0x00000000 +#define Fp F5 +#define Kp 0x50A28BE6 + P2(A, B, C, D, E, 0, 11, 5, 8); + P2(E, A, B, C, D, 1, 14, 14, 9); + P2(D, E, A, B, C, 2, 15, 7, 9); + P2(C, D, E, A, B, 3, 12, 0, 11); + P2(B, C, D, E, A, 4, 5, 9, 13); + P2(A, B, C, D, E, 5, 8, 2, 15); + P2(E, A, B, C, D, 6, 7, 11, 15); + P2(D, E, A, B, C, 7, 9, 4, 5); + P2(C, D, E, A, B, 8, 11, 13, 7); + P2(B, C, D, E, A, 9, 13, 6, 7); + P2(A, B, C, D, E, 10, 14, 15, 8); + P2(E, A, B, C, D, 11, 15, 8, 11); + P2(D, E, A, B, C, 12, 6, 1, 14); + P2(C, D, E, A, B, 13, 7, 10, 14); + P2(B, C, D, E, A, 14, 9, 3, 12); + P2(A, B, C, D, E, 15, 8, 12, 6); +#undef F +#undef K +#undef Fp +#undef Kp + +#define F F2 +#define K 0x5A827999 +#define Fp F4 +#define Kp 0x5C4DD124 + P2(E, A, B, C, D, 7, 7, 6, 9); + P2(D, E, A, B, C, 4, 6, 11, 13); + P2(C, D, E, A, B, 13, 8, 3, 15); + P2(B, C, D, E, A, 1, 13, 7, 7); + P2(A, B, C, D, E, 10, 11, 0, 12); + P2(E, A, B, C, D, 6, 9, 13, 8); + P2(D, E, A, B, C, 15, 7, 5, 9); + P2(C, D, E, A, B, 3, 15, 10, 11); + P2(B, C, D, E, A, 12, 7, 14, 7); + P2(A, B, C, D, E, 0, 12, 15, 7); + P2(E, A, B, C, D, 9, 15, 8, 12); + P2(D, E, A, B, C, 5, 9, 12, 7); + P2(C, D, E, A, B, 2, 11, 4, 6); + P2(B, C, D, E, A, 14, 7, 9, 15); + P2(A, B, C, D, E, 11, 13, 1, 13); + P2(E, A, B, C, D, 8, 12, 2, 11); +#undef F +#undef K +#undef Fp +#undef Kp + +#define F F3 +#define K 0x6ED9EBA1 +#define Fp F3 +#define Kp 0x6D703EF3 + P2(D, E, A, B, C, 3, 11, 15, 9); + P2(C, D, E, A, B, 10, 13, 5, 7); + P2(B, C, D, E, A, 14, 6, 1, 15); + P2(A, B, C, D, E, 4, 7, 3, 11); + P2(E, A, B, C, D, 9, 14, 7, 8); + P2(D, E, A, B, C, 15, 9, 14, 6); + P2(C, D, E, A, B, 8, 13, 6, 6); + P2(B, C, D, E, A, 1, 15, 9, 14); + P2(A, B, C, D, E, 2, 14, 11, 12); + P2(E, A, B, C, D, 7, 8, 8, 13); + P2(D, E, A, B, C, 0, 13, 12, 5); + P2(C, D, E, A, B, 6, 6, 2, 14); + P2(B, C, D, E, A, 13, 5, 10, 13); + P2(A, B, C, D, E, 11, 12, 0, 13); + P2(E, A, B, C, D, 5, 7, 4, 7); + P2(D, E, A, B, C, 12, 5, 13, 5); +#undef F +#undef K +#undef Fp +#undef Kp + +#define F F4 +#define K 0x8F1BBCDC +#define Fp F2 +#define Kp 0x7A6D76E9 + P2(C, D, E, A, B, 1, 11, 8, 15); + P2(B, C, D, E, A, 9, 12, 6, 5); + P2(A, B, C, D, E, 11, 14, 4, 8); + P2(E, A, B, C, D, 10, 15, 1, 11); + P2(D, E, A, B, C, 0, 14, 3, 14); + P2(C, D, E, A, B, 8, 15, 11, 14); + P2(B, C, D, E, A, 12, 9, 15, 6); + P2(A, B, C, D, E, 4, 8, 0, 14); + P2(E, A, B, C, D, 13, 9, 5, 6); + P2(D, E, A, B, C, 3, 14, 12, 9); + P2(C, D, E, A, B, 7, 5, 2, 12); + P2(B, C, D, E, A, 15, 6, 13, 9); + P2(A, B, C, D, E, 14, 8, 9, 12); + P2(E, A, B, C, D, 5, 6, 7, 5); + P2(D, E, A, B, C, 6, 5, 10, 15); + P2(C, D, E, A, B, 2, 12, 14, 8); +#undef F +#undef K +#undef Fp +#undef Kp + +#define F F5 +#define K 0xA953FD4E +#define Fp F1 +#define Kp 0x00000000 + P2(B, C, D, E, A, 4, 9, 12, 8); + P2(A, B, C, D, E, 0, 15, 15, 5); + P2(E, A, B, C, D, 5, 5, 10, 12); + P2(D, E, A, B, C, 9, 11, 4, 9); + P2(C, D, E, A, B, 7, 6, 1, 12); + P2(B, C, D, E, A, 12, 8, 5, 5); + P2(A, B, C, D, E, 2, 13, 8, 14); + P2(E, A, B, C, D, 10, 12, 7, 6); + P2(D, E, A, B, C, 14, 5, 6, 8); + P2(C, D, E, A, B, 1, 12, 2, 13); + P2(B, C, D, E, A, 3, 13, 13, 6); + P2(A, B, C, D, E, 8, 14, 14, 5); + P2(E, A, B, C, D, 11, 11, 0, 15); + P2(D, E, A, B, C, 6, 8, 3, 13); + P2(C, D, E, A, B, 15, 5, 9, 11); + P2(B, C, D, E, A, 13, 6, 11, 11); +#undef F +#undef K +#undef Fp +#undef Kp + + C = ctx->state[1] + C + Dp; + ctx->state[1] = ctx->state[2] + D + Ep; + ctx->state[2] = ctx->state[3] + E + Ap; + ctx->state[3] = ctx->state[4] + A + Bp; + ctx->state[4] = ctx->state[0] + B + Cp; + ctx->state[0] = C; +} +#endif /* !MBEDTLS_RIPEMD160_PROCESS_ALT */ + +/* + * RIPEMD-160 process buffer + */ +void ripemd160_Update(RIPEMD160_CTX* ctx, const uint8_t* input, uint32_t ilen) { + uint32_t fill = 0; + uint32_t left = 0; + + if(ilen == 0) return; + + left = ctx->total[0] & 0x3F; + fill = RIPEMD160_BLOCK_LENGTH - left; + + ctx->total[0] += (uint32_t)ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if(ctx->total[0] < (uint32_t)ilen) ctx->total[1]++; + + if(left && ilen >= fill) { + memcpy((void*)(ctx->buffer + left), input, fill); + ripemd160_process(ctx, ctx->buffer); + input += fill; + ilen -= fill; + left = 0; + } + + while(ilen >= RIPEMD160_BLOCK_LENGTH) { + ripemd160_process(ctx, input); + input += RIPEMD160_BLOCK_LENGTH; + ilen -= RIPEMD160_BLOCK_LENGTH; + } + + if(ilen > 0) { + memcpy((void*)(ctx->buffer + left), input, ilen); + } +} + +static const uint8_t ripemd160_padding[RIPEMD160_BLOCK_LENGTH] = { + 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, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +/* + * RIPEMD-160 final digest + */ +void ripemd160_Final(RIPEMD160_CTX* ctx, uint8_t output[RIPEMD160_DIGEST_LENGTH]) { + uint32_t last = 0; + uint32_t padn = 0; + uint32_t high = 0; + uint32_t low = 0; + uint8_t msglen[8] = {0}; + + high = (ctx->total[0] >> 29) | (ctx->total[1] << 3); + low = (ctx->total[0] << 3); + + PUT_UINT32_LE(low, msglen, 0); + PUT_UINT32_LE(high, msglen, 4); + + last = ctx->total[0] & 0x3F; + padn = (last < 56) ? (56 - last) : (120 - last); + + ripemd160_Update(ctx, ripemd160_padding, padn); + ripemd160_Update(ctx, msglen, 8); + + PUT_UINT32_LE(ctx->state[0], output, 0); + PUT_UINT32_LE(ctx->state[1], output, 4); + PUT_UINT32_LE(ctx->state[2], output, 8); + PUT_UINT32_LE(ctx->state[3], output, 12); + PUT_UINT32_LE(ctx->state[4], output, 16); + + memzero(ctx, sizeof(RIPEMD160_CTX)); +} + +/* + * output = RIPEMD-160( input buffer ) + */ +void ripemd160(const uint8_t* msg, uint32_t msg_len, uint8_t hash[RIPEMD160_DIGEST_LENGTH]) { + RIPEMD160_CTX ctx = {0}; + ripemd160_Init(&ctx); + ripemd160_Update(&ctx, msg, msg_len); + ripemd160_Final(&ctx, hash); +} diff --git a/applications/external/flipbip/lib/crypto/ripemd160.h b/applications/external/flipbip/lib/crypto/ripemd160.h new file mode 100644 index 000000000..271e9ec5b --- /dev/null +++ b/applications/external/flipbip/lib/crypto/ripemd160.h @@ -0,0 +1,20 @@ +#ifndef __RIPEMD160_H__ +#define __RIPEMD160_H__ + +#include + +#define RIPEMD160_BLOCK_LENGTH 64 +#define RIPEMD160_DIGEST_LENGTH 20 + +typedef struct _RIPEMD160_CTX { + uint32_t total[2]; /*!< number of bytes processed */ + uint32_t state[5]; /*!< intermediate digest state */ + uint8_t buffer[RIPEMD160_BLOCK_LENGTH]; /*!< data block being processed */ +} RIPEMD160_CTX; + +void ripemd160_Init(RIPEMD160_CTX* ctx); +void ripemd160_Update(RIPEMD160_CTX* ctx, const uint8_t* input, uint32_t ilen); +void ripemd160_Final(RIPEMD160_CTX* ctx, uint8_t output[RIPEMD160_DIGEST_LENGTH]); +void ripemd160(const uint8_t* msg, uint32_t msg_len, uint8_t hash[RIPEMD160_DIGEST_LENGTH]); + +#endif diff --git a/applications/external/flipbip/lib/crypto/script.c b/applications/external/flipbip/lib/crypto/script.c new file mode 100644 index 000000000..11173e973 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/script.c @@ -0,0 +1,64 @@ +/** + * Copyright (c) 2016 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "script.h" +#include +#include "base58.h" + +int script_output_to_address(const uint8_t* script, int scriptlen, char* addr, int addrsize) { + uint8_t raw[35] = {0}; + + // P2PKH + if(scriptlen == 25 && script[0] == 0x76 && script[1] == 0xA9 && script[2] == 0x14 && + script[23] == 0x88 && script[24] == 0xAC) { + raw[0] = 0x00; + memcpy(raw + 1, script + 3, 20); + return base58_encode_check(raw, 1 + 20, HASHER_SHA2D, addr, addrsize); + } + + // P2SH + if(scriptlen == 23 && script[0] == 0xA9 && script[1] == 0x14 && script[22] == 0x87) { + raw[0] = 0x05; + memcpy(raw + 1, script + 2, 20); + return base58_encode_check(raw, 1 + 20, HASHER_SHA2D, addr, addrsize); + } + + // P2WPKH + if(scriptlen == 22 && script[0] == 0x00 && script[1] == 0x14) { + raw[0] = 0x06; + raw[1] = 0x00; + raw[2] = 0x00; + memcpy(raw + 3, script + 2, 20); + return base58_encode_check(raw, 3 + 20, HASHER_SHA2D, addr, addrsize); + } + + // P2WSH + if(scriptlen == 34 && script[0] == 0x00 && script[1] == 0x20) { + raw[0] = 0x0A; + raw[1] = 0x00; + raw[2] = 0x00; + memcpy(raw + 3, script + 2, 32); + return base58_encode_check(raw, 3 + 32, HASHER_SHA2D, addr, addrsize); + } + + return 0; +} diff --git a/applications/external/flipbip/lib/crypto/script.h b/applications/external/flipbip/lib/crypto/script.h new file mode 100644 index 000000000..585b059fa --- /dev/null +++ b/applications/external/flipbip/lib/crypto/script.h @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2016 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __SCRIPT_H__ +#define __SCRIPT_H__ + +#include + +int script_output_to_address(const uint8_t* script, int scriptlen, char* addr, int addrsize); + +#endif diff --git a/applications/external/flipbip/lib/crypto/secp256k1.c b/applications/external/flipbip/lib/crypto/secp256k1.c new file mode 100644 index 000000000..d954dd733 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/secp256k1.c @@ -0,0 +1,135 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "secp256k1.h" + +const ecdsa_curve secp256k1 = { + /* .prime */ {/*.val =*/{ + 0x1ffffc2f, + 0x1ffffff7, + 0x1fffffff, + 0x1fffffff, + 0x1fffffff, + 0x1fffffff, + 0x1fffffff, + 0x1fffffff, + 0xffffff}}, + + /* G */ + {/*.x =*/{/*.val =*/{ + 0x16f81798, + 0x0f940ad8, + 0x138a3656, + 0x17f9b65b, + 0x10b07029, + 0x114ae743, + 0x0eb15681, + 0x0fdf3b97, + 0x79be66}}, + /*.y =*/{/*.val =*/{ + 0x1b10d4b8, + 0x023e847f, + 0x01550667, + 0x0f68914d, + 0x108a8fd1, + 0x1dfe0708, + 0x11957693, + 0x0ee4d478, + 0x483ada}}}, + + /* order */ + {/*.val =*/{ + 0x10364141, + 0x1e92f466, + 0x12280eef, + 0x1db9cd5e, + 0x1fffebaa, + 0x1fffffff, + 0x1fffffff, + 0x1fffffff, + 0xffffff}}, + + /* order_half */ + {/*.val =*/{ + 0x081b20a0, + 0x1f497a33, + 0x09140777, + 0x0edce6af, + 0x1ffff5d5, + 0x1fffffff, + 0x1fffffff, + 0x1fffffff, + 0x7fffff}}, + + /* a */ 0, + + /* b */ {/*.val =*/{7}} + +#if USE_PRECOMPUTED_CP + , + /* cp */ + { +#include "secp256k1.table" + } +#endif +}; + +const curve_info secp256k1_info = { + .bip32_name = "Bitcoin seed", + .params = &secp256k1, + .hasher_base58 = HASHER_SHA2D, + .hasher_sign = HASHER_SHA2D, + .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_script = HASHER_SHA2, +}; + +const curve_info secp256k1_decred_info = { + .bip32_name = "Bitcoin seed", + .params = &secp256k1, + .hasher_base58 = HASHER_BLAKED, + .hasher_sign = HASHER_BLAKE, + .hasher_pubkey = HASHER_BLAKE_RIPEMD, + .hasher_script = HASHER_BLAKE, +}; + +const curve_info secp256k1_groestl_info = { + .bip32_name = "Bitcoin seed", + .params = &secp256k1, + .hasher_base58 = HASHER_GROESTLD_TRUNC, + .hasher_sign = HASHER_SHA2, + .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_script = HASHER_SHA2, +}; + +const curve_info secp256k1_smart_info = { + .bip32_name = "Bitcoin seed", + .params = &secp256k1, +#if USE_KECCAK + .hasher_base58 = HASHER_SHA3K, +#else + .hasher_base58 = HASHER_SHA3, +#endif + .hasher_sign = HASHER_SHA2, + .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_script = HASHER_SHA2, +}; diff --git a/applications/external/flipbip/lib/crypto/secp256k1.h b/applications/external/flipbip/lib/crypto/secp256k1.h new file mode 100644 index 000000000..3b45e48fe --- /dev/null +++ b/applications/external/flipbip/lib/crypto/secp256k1.h @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __SECP256K1_H__ +#define __SECP256K1_H__ + +#include + +#include "bip32.h" +#include "ecdsa.h" + +extern const ecdsa_curve secp256k1; +extern const curve_info secp256k1_info; +extern const curve_info secp256k1_decred_info; +extern const curve_info secp256k1_groestl_info; +extern const curve_info secp256k1_smart_info; + +#endif diff --git a/applications/external/flipbip/lib/crypto/secp256k1.table b/applications/external/flipbip/lib/crypto/secp256k1.table new file mode 100644 index 000000000..0fa87a8b1 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/secp256k1.table @@ -0,0 +1,1664 @@ + { + /* 1*16^0*G: */ + {{{0x16f81798, 0x0f940ad8, 0x138a3656, 0x17f9b65b, 0x10b07029, 0x114ae743, 0x0eb15681, 0x0fdf3b97, 0x79be66}}, + {{0x1b10d4b8, 0x023e847f, 0x01550667, 0x0f68914d, 0x108a8fd1, 0x1dfe0708, 0x11957693, 0x0ee4d478, 0x483ada}}}, + /* 3*16^0*G: */ + {{{0x1ce036f9, 0x100f889d, 0x1be66c21, 0x03908b06, 0x15229b53, 0x07c2fc4e, 0x0c4124d1, 0x00324b18, 0xf9308a}}, + {{0x04b8e672, 0x05cfebac, 0x1088c6db, 0x01533269, 0x1f356650, 0x1bf3151b, 0x00503f8c, 0x01ec65bd, 0x388f7b}}}, + /* 5*16^0*G: */ + {{{0x1240efe4, 0x1d46ab4d, 0x1866adf2, 0x17097bb8, 0x05128e88, 0x1392852e, 0x024d56d2, 0x09a340e4, 0x2f8bde}}, + {{0x06ac62d6, 0x0543e9d5, 0x035a1037, 0x104e3756, 0x1c426f78, 0x14eed364, 0x0f5b536e, 0x04c6dcbc, 0xd8ac22}}}, + /* 7*16^0*G: */ + {{{0x0ac4f9bc, 0x095eef6e, 0x0c38e73a, 0x0336fc06, 0x07a0e3d4, 0x19b2f975, 0x13aa8e63, 0x0c8dcbb6, 0x5cbdf0}}, + {{0x087264da, 0x08413140, 0x1f79ed69, 0x07a17027, 0x054dba81, 0x06b6c30d, 0x05828c5e, 0x081744ab, 0x6aebca}}}, + /* 9*16^0*G: */ + {{{0x1c27ccbe, 0x1af8886f, 0x15f9c530, 0x0f2d2e98, 0x19abde09, 0x0bc54faa, 0x194c26b4, 0x1c5e18fe, 0xacd484}}, + {{0x064f9c37, 0x0e613156, 0x17e383c1, 0x1111486e, 0x161e9add, 0x04b8bb1d, 0x07f590e0, 0x043614fb, 0xcc3389}}}, + /* 11*16^0*G: */ + {{{0x1da008cb, 0x1f60bc4a, 0x105e246e, 0x133017cb, 0x05aac564, 0x1235b863, 0x04797bd0, 0x1f0b1528, 0x774ae7}}, + {{0x0953c61b, 0x00eba64e, 0x1e75aa0c, 0x1b63c5bf, 0x1b365372, 0x0eab6bdb, 0x1864090f, 0x065d6d6b, 0xd984a0}}}, + /* 13*16^0*G: */ + {{{0x19405aa8, 0x176efc78, 0x03963377, 0x0bf78cc2, 0x08651b07, 0x0902e1ba, 0x022f1f47, 0x185b2ea5, 0xf28773}}, + {{0x1b03ed81, 0x0dae5a96, 0x07ea47ca, 0x140db4a4, 0x1af473a1, 0x0975b2e6, 0x0a25d608, 0x05d1b101, 0xab090}}}, + /* 15*16^0*G: */ + {{{0x027e080e, 0x056de7c7, 0x017de791, 0x0b28de79, 0x1f41131e, 0x0d7184af, 0x0a596919, 0x09efa87d, 0xd7924d}}, + {{0x16a26b58, 0x0826e4ff, 0x05b4e971, 0x015e57b1, 0x06defea4, 0x17611466, 0x0a9a0e10, 0x0e550d8e, 0x581e28}}} + }, + { + /* 1*16^1*G: */ + {{{0x0a6dec0a, 0x027744f1, 0x1e96ba71, 0x0626d370, 0x03e97b2a, 0x155e10e1, 0x1b14c046, 0x1276b3d3, 0xe60fce}}, + {{0x09616821, 0x0f996673, 0x148fc2f8, 0x0d123c89, 0x13710129, 0x0f9a7abc, 0x164a76e6, 0x0e733cb2, 0xf7e350}}}, + /* 3*16^1*G: */ + {{{0x1118e5c3, 0x1ec38550, 0x0afaf066, 0x0f364e8a, 0x05b4bfc5, 0x12b77a73, 0x01f6d105, 0x0bb2c8a6, 0x6eca33}}, + {{0x05a08668, 0x0c517bc0, 0x1e3b0d12, 0x12d47477, 0x075a03a4, 0x0bc83a5c, 0x1c4164bd, 0x16af4f40, 0xd50123}}}, + /* 5*16^1*G: */ + {{{0x0f87f62e, 0x16698f0a, 0x1c5849c3, 0x0dcc70c6, 0x059f010e, 0x1a2769a3, 0x03b035f1, 0x17de37f2, 0xe9623b}}, + {{0x044ee737, 0x1809f57d, 0x1a211394, 0x008793ba, 0x0a929fe6, 0x0a9d476d, 0x07a783fa, 0x07697853, 0x38a974}}}, + /* 7*16^1*G: */ + {{{0x0a8d733c, 0x18556fc1, 0x1f2a3e7a, 0x04e97ec5, 0x0d682ffc, 0x11b79040, 0x16e82212, 0x0e7ca2c3, 0xbc82dd}}, + {{0x147797f0, 0x13c30827, 0x0e25cc07, 0x074175ce, 0x102dfae9, 0x1a5fb8cf, 0x12b152a6, 0x07408963, 0xe5f28c}}}, + /* 9*16^1*G: */ + {{{0x1fbc7671, 0x1f7f118a, 0x01638cb5, 0x1e3790a5, 0x0f490743, 0x08e70bcc, 0x0847480a, 0x0918ecae, 0x8e3d12}}, + {{0x18717dec, 0x178ee320, 0x0f85129f, 0x0a57554c, 0x1e90eb93, 0x0070c9c9, 0x0e07d912, 0x1c21d9f9, 0x99a48}}}, + /* 11*16^1*G: */ + {{{0x1eb31db2, 0x1943a195, 0x1d41a83c, 0x15d04f11, 0x0a2b68fc, 0x0c9f6844, 0x126225a8, 0x15444694, 0x78a891}}, + {{0x19fa4343, 0x034eb11d, 0x002e0b4c, 0x0f379bb0, 0x02df6543, 0x192a9398, 0x172ff3d7, 0x0b7d6a06, 0x6912a3}}}, + /* 13*16^1*G: */ + {{{0x0db0e595, 0x09a47bbc, 0x0820aed9, 0x0c7973f7, 0x076eba71, 0x1bb2c0b0, 0x0c5f5f38, 0x030abb63, 0x7d8678}}, + {{0x1c733de8, 0x0ca8f1d5, 0x09754ca6, 0x0f089c1c, 0x18838293, 0x1715f6a7, 0x01dcb958, 0x1bfd90df, 0xe2b99a}}}, + /* 15*16^1*G: */ + {{{0x16060dfc, 0x047f7c28, 0x179a8a80, 0x08bf0840, 0x0b086765, 0x05cee20d, 0x0b212125, 0x01e00b05, 0xddc531}}, + {{0x07820ca8, 0x1afc55b7, 0x1411cc3e, 0x175f8d57, 0x10e9041d, 0x15b6e647, 0x1a480646, 0x075e41b2, 0xba0d2f}}} + }, + { + /* 1*16^2*G: */ + {{{0x15f51508, 0x123711fe, 0x0b072841, 0x073957ab, 0x1e238d8c, 0x171f0b96, 0x0767a8a9, 0x064258c1, 0x828226}}, + {{0x16e26caf, 0x18db757f, 0x1ec5efb4, 0x0c27585e, 0x00ace62d, 0x0b74185b, 0x1f917a09, 0x0130aafb, 0x11f8a8}}}, + /* 3*16^2*G: */ + {{{0x057e8dfa, 0x07e065cf, 0x11f8613f, 0x01232347, 0x18ca0098, 0x187c5654, 0x11303668, 0x05fe0f33, 0x8262cf}}, + {{0x1bac376a, 0x0e7fc6c7, 0x05311e0d, 0x0dda6656, 0x14f3457b, 0x111762d9, 0x19399bfb, 0x1c412213, 0x83fd95}}}, + /* 5*16^2*G: */ + {{{0x026bdb6f, 0x02972458, 0x1cd2e524, 0x0837a8f6, 0x19c877ca, 0x02d92674, 0x17545a04, 0x1163b41b, 0x19825c}}, + {{0x049cfc9b, 0x0efb8426, 0x1db4e9ad, 0x13dd9919, 0x19f6cebe, 0x10e64a7a, 0x1e3cc809, 0x01e1a990, 0x629431}}}, + /* 7*16^2*G: */ + {{{0x1d82824c, 0x07684a91, 0x054d3994, 0x0b1c68bc, 0x0999edfa, 0x1ab76361, 0x04510f17, 0x0d822c03, 0x6f12d8}}, + {{0x06eb34d0, 0x0bce1a40, 0x152f16e1, 0x19248210, 0x03769391, 0x0a79feb1, 0x1e821d66, 0x1e895677, 0x5c4ff7}}}, + /* 9*16^2*G: */ + {{{0x1b453629, 0x1b6ee016, 0x167980c1, 0x1fb9b81e, 0x0bef645c, 0x138b511d, 0x09745098, 0x0df34155, 0x203a8c}}, + {{0x1ff89f84, 0x0b8e3c29, 0x0a17b516, 0x1bd64b8a, 0x10612686, 0x1b68afa0, 0x06e4db31, 0x0a7bcbbb, 0x3b0f0b}}}, + /* 11*16^2*G: */ + {{{0x046c7ecb, 0x018986ef, 0x0ed33a5e, 0x15da7fcb, 0x0e1ec9d3, 0x1b99a433, 0x0607207b, 0x1d67a068, 0x6e2aca}}, + {{0x0ebc8720, 0x024900f7, 0x19d44b21, 0x0e0d7236, 0x1643afac, 0x026d787d, 0x18527603, 0x0cf2fdfd, 0x9e61a4}}}, + /* 13*16^2*G: */ + {{{0x10a4147e, 0x1b80c79f, 0x1d7c807a, 0x0fbb17ee, 0x10a58274, 0x18bf4524, 0x15aebd85, 0x125d3d22, 0xd5a704}}, + {{0x13fb65ff, 0x1259e5c1, 0x19fd5fe3, 0x09b308f2, 0x00532f4c, 0x04c83b2f, 0x071bf124, 0x1ebb7571, 0x9db526}}}, + /* 15*16^2*G: */ + {{{0x18edcec6, 0x16eda35e, 0x18d3d153, 0x0c3985a6, 0x0dac6a10, 0x17e31816, 0x0ea0148f, 0x13557c31, 0x38c511}}, + {{0x1933db08, 0x0b705fd8, 0x154c2991, 0x02d90456, 0x1282f28a, 0x196d13af, 0x0ca99a32, 0x0450bb2e, 0xe649dd}}} + }, + { + /* 1*16^3*G: */ + {{{0x11e5b739, 0x1fe72daa, 0x0888bb5c, 0x127067fa, 0x0846de0b, 0x0e63637e, 0x1969cbe6, 0x13ee5170, 0x175e15}}, + {{0x09fed695, 0x17d37ff7, 0x090d171b, 0x0b2ab5ba, 0x11f5eacb, 0x0bd28ffb, 0x07ae93be, 0x01b3c78f, 0xd3506e}}}, + /* 3*16^3*G: */ + {{{0x05041216, 0x0dbfc78e, 0x0ae0da99, 0x066bed08, 0x1ed523f7, 0x0cf7ee17, 0x13d04a2d, 0x0f643ef5, 0xda7531}}, + {{0x0e708572, 0x176994c3, 0x1eb3b6b6, 0x1580f5ce, 0x17fc6e9a, 0x110d9a16, 0x17c37c67, 0x08d7ee5a, 0x73f8a0}}}, + /* 5*16^3*G: */ + {{{0x0465a930, 0x00a1f38f, 0x04d4bf6c, 0x0fe382d6, 0x0eb1e258, 0x02c62541, 0x075c15cf, 0x1691d2e9, 0x1c71c5}}, + {{0x034638b5, 0x0c39fb66, 0x05d351c7, 0x08bc7f6e, 0x1b68c793, 0x18f94125, 0x08309c4f, 0x069d1ebf, 0x4a91c3}}}, + /* 7*16^3*G: */ + {{{0x1adb6ee7, 0x18c6d72d, 0x11281df8, 0x01ba864e, 0x14c9c785, 0x01bd484d, 0x159a4dba, 0x1f83e634, 0xd84e4a}}, + {{0x142ebed2, 0x16aab736, 0x08f99260, 0x11592e95, 0x1de4dfdd, 0x06ac7ab2, 0x07384a8e, 0x134f8f6f, 0xe52580}}}, + /* 9*16^3*G: */ + {{{0x049e6d10, 0x0a74f67d, 0x0b26748e, 0x15bfe75d, 0x16ed3f60, 0x15c942ff, 0x053506c8, 0x097bccd0, 0xf3d444}}, + {{0x1347da3f, 0x101c6602, 0x075b18c2, 0x15b4a19d, 0x04b5bfc1, 0x0ad60cc5, 0x18f52eae, 0x1bf4de02, 0xa4324}}}, + /* 11*16^3*G: */ + {{{0x09d33a07, 0x0659a037, 0x0e6f2ad2, 0x05dc1154, 0x1f4044e7, 0x0a9066de, 0x1627e421, 0x0593b383, 0xae3065}}, + {{0x00a0b2a6, 0x0438607b, 0x15fa571d, 0x186febbf, 0x0d5cf1c9, 0x13e99edc, 0x195fbf33, 0x1871ac7f, 0x6cb9d9}}}, + /* 13*16^3*G: */ + {{{0x0c28caca, 0x0cb2a5c8, 0x00a0769d, 0x138f7799, 0x08c9a186, 0x1f3ac19c, 0x07205785, 0x054b7abc, 0xd8dc1b}}, + {{0x03b3ec7a, 0x0db3b751, 0x004a3db3, 0x02ba59d9, 0x07d947d3, 0x06d21012, 0x1f5631b6, 0x1b24f9d8, 0x8cec0a}}}, + /* 15*16^3*G: */ + {{{0x1bc4416f, 0x090fdb31, 0x02c100a2, 0x1dfa47e6, 0x0f31da7a, 0x12d46819, 0x1b335650, 0x1258bf09, 0x2749e2}}, + {{0x1c6bbd8e, 0x14c5ef17, 0x1a58415f, 0x1d3f6cbd, 0x0db3ef59, 0x0a4c87e5, 0x0f1100f6, 0x09c6ece5, 0x50cc2d}}} + }, + { + /* 1*16^4*G: */ + {{{0x03ff4640, 0x135d6c7c, 0x154bff94, 0x0838fcaa, 0x02ee0534, 0x1602db13, 0x1272673a, 0x1a88f601, 0x363d90}}, + {{0x1bee9de9, 0x1001e3f9, 0x0667b2d8, 0x13512010, 0x1363145b, 0x0229cbf9, 0x088654ed, 0x15bf8e64, 0x4e273}}}, + /* 3*16^4*G: */ + {{{0x16e55dc8, 0x1c4890b7, 0x12810e52, 0x12b56dd5, 0x094426ff, 0x12206028, 0x1ecaea12, 0x08f218bf, 0x443140}}, + {{0x1be323b3, 0x0eca2576, 0x0a8b940c, 0x14536f3d, 0x0fed7a66, 0x01bfab21, 0x1be3fa66, 0x085cca6c, 0x96b0c1}}}, + /* 5*16^4*G: */ + {{{0x101b23a8, 0x1f4a42eb, 0x01fb82b7, 0x16fa8e15, 0x1089dab7, 0x01eadc90, 0x01f04989, 0x11b0cd95, 0x9e22fe}}, + {{0x0884edae, 0x1d209e28, 0x14473b3d, 0x0f9293f6, 0x01533c0f, 0x1f8104ce, 0x14405dfc, 0x1d394245, 0xfd2ff0}}}, + /* 7*16^4*G: */ + {{{0x071a70e4, 0x0ba045f8, 0x173d1d77, 0x1dca3ebe, 0x1306dcd5, 0x14f32382, 0x0a34bb75, 0x1aa079c5, 0x508df6}}, + {{0x09950984, 0x1972dfb9, 0x02ab7fb7, 0x006451dd, 0x049c54ec, 0x0255399f, 0x10b5ddcc, 0x13726778, 0x154c43}}}, + /* 9*16^4*G: */ + {{{0x0e1abe11, 0x157ed3b6, 0x12c883db, 0x124384b3, 0x125b2dab, 0x1ac0c980, 0x1d8cce37, 0x108aa212, 0xe3dbff}}, + {{0x1fa8de63, 0x1a4d6aa4, 0x1ad71052, 0x12fb2078, 0x08ef3d3c, 0x1d3aedc5, 0x108590e3, 0x01334682, 0x6f2f9}}}, + /* 11*16^4*G: */ + {{{0x03593449, 0x078d91b0, 0x0a91bff7, 0x16f825c8, 0x1014af61, 0x0e09d03e, 0x10361e36, 0x0c98fbd2, 0x19ace0}}, + {{0x0df83631, 0x120a5c9d, 0x0101a28e, 0x02173e81, 0x02c46ac7, 0x0b9ceca0, 0x0cceffaf, 0x006a4d14, 0xe37992}}}, + /* 13*16^4*G: */ + {{{0x0cba6b63, 0x11f4c496, 0x02ceed7b, 0x1fcce9fa, 0x08e310a0, 0x19914754, 0x16a84230, 0x1d841f0f, 0xd8740c}}, + {{0x0934c5f3, 0x1751b603, 0x005a52af, 0x009eb987, 0x0c37d401, 0x1774c81d, 0x0afcde29, 0x0678d726, 0x6472c1}}}, + /* 15*16^4*G: */ + {{{0x1b3ec038, 0x0ca7f960, 0x031ac9d8, 0x1aa2d5cc, 0x10a50d9f, 0x1f3b1794, 0x020d9220, 0x07236a0c, 0x58ac33}}, + {{0x10246279, 0x17551f88, 0x13eef285, 0x12087816, 0x1fe97021, 0x0924f4c8, 0x0b65e1de, 0x00daab92, 0x9163d7}}} + }, + { + /* 1*16^5*G: */ + {{{0x1ffdf80c, 0x0fbcd2ae, 0x16f346da, 0x094f0342, 0x1638843e, 0x025adba2, 0x0afa3189, 0x02cbbe78, 0x8b4b5f}}, + {{0x1fd4fd36, 0x1f7f8632, 0x18bb95ac, 0x066ca8c2, 0x0da04f9e, 0x0bc09d58, 0x02d2cfef, 0x0ded1a61, 0x4aad0a}}}, + /* 3*16^5*G: */ + {{{0x155812dd, 0x05152c17, 0x0b4c38a8, 0x08ce46aa, 0x0f78e3d4, 0x1f6b602c, 0x14bc2daa, 0x0f525fe6, 0x7029bd}}, + {{0x1a2d2927, 0x10e63358, 0x0cb1cf1c, 0x15d08487, 0x083ac47d, 0x0a257183, 0x0f49f759, 0x1b5fbd16, 0xb0eefa}}}, + /* 5*16^5*G: */ + {{{0x1d486ed1, 0x0e72b41d, 0x1596da92, 0x0b7d7492, 0x17560574, 0x0084ec67, 0x12640275, 0x195d5ccb, 0x9ccfed}}, + {{0x15e95d8d, 0x1b6acf6b, 0x164aa893, 0x02ceb2d2, 0x13411242, 0x12409005, 0x0b3ed848, 0x0e27ad46, 0x7c2f4d}}}, + /* 7*16^5*G: */ + {{{0x1bd0eaca, 0x10358d3a, 0x0b52ade8, 0x0e8aed74, 0x0df19d0c, 0x1ef19e52, 0x050cd6a3, 0x10ec6828, 0xcd9a4b}}, + {{0x0bff4acc, 0x137d7dad, 0x1bd8d3db, 0x0f671dda, 0x0a08b012, 0x0457499f, 0x08fa0552, 0x0f343d1e, 0xf04558}}}, + /* 9*16^5*G: */ + {{{0x07bc57c6, 0x104a9d1e, 0x0c9db2fc, 0x07af447d, 0x03094490, 0x169749eb, 0x0faa213c, 0x05f11db3, 0xad0988}}, + {{0x0e4a0ab8, 0x1196076d, 0x0438b4f2, 0x023a6e6b, 0x0be5f7b3, 0x036394ed, 0x14ae8a06, 0x11885f74, 0x7243c0}}}, + /* 11*16^5*G: */ + {{{0x0ba56302, 0x14186395, 0x03c618ba, 0x0d526f5e, 0x0d2e0f50, 0x116954fd, 0x107c7ab6, 0x015d6794, 0xd9d129}}, + {{0x08291c29, 0x156ed7d4, 0x09d3caba, 0x135d9b3f, 0x186e4173, 0x0ae33931, 0x1bb40a5c, 0x027d85a7, 0x7eb531}}}, + /* 13*16^5*G: */ + {{{0x14d1243a, 0x1669b827, 0x15297f6e, 0x024c047e, 0x1558402b, 0x10d6031f, 0x13be4734, 0x1bca73ad, 0xbc5079}}, + {{0x055db68a, 0x0e4a8b44, 0x1d1c5a7d, 0x1dc9eb63, 0x1c8d75f7, 0x195ca6ff, 0x12ee3bb1, 0x07674e0b, 0x65062a}}}, + /* 15*16^5*G: */ + {{{0x174a3f9f, 0x06922735, 0x02605a42, 0x0f4ccbb8, 0x0625ac28, 0x15573ed9, 0x1fa244f7, 0x0fca0bf8, 0x4d31a7}}, + {{0x101e0ba7, 0x1e581209, 0x18029d53, 0x0df6a36d, 0x02753cbf, 0x079c63c0, 0x1d6c1ac6, 0x192c130a, 0x22241e}}} + }, + { + /* 1*16^6*G: */ + {{{0x1232fcda, 0x1b08ac92, 0x1039def2, 0x01b7ff4d, 0x148c7b70, 0x18e005ea, 0x05b5afdd, 0x14dcbb73, 0x723cba}}, + {{0x1eb39f5f, 0x0ee034ec, 0x1e525200, 0x0140ca6e, 0x04d6e266, 0x09ba4441, 0x1262a484, 0x16ab2b98, 0x96e867}}}, + /* 3*16^6*G: */ + {{{0x00633cb1, 0x0b3f04f4, 0x140844c9, 0x144496d3, 0x01fcb575, 0x1399090c, 0x0b500318, 0x1e62f559, 0x6dde9c}}, + {{0x07ce6b34, 0x1eea4d53, 0x0167bcd5, 0x04ffb59f, 0x066a880b, 0x17c350dd, 0x10757267, 0x1cf4e0fc, 0x9188fb}}}, + /* 5*16^6*G: */ + {{{0x0933f3c5, 0x0cd28c69, 0x1c494890, 0x141ee22b, 0x1b850085, 0x1dbfc723, 0x17a04f12, 0x059ab6b9, 0x486fa7}}, + {{0x0afb0f53, 0x16a538d6, 0x03c8ede6, 0x136f079e, 0x0f19f62d, 0x045d7664, 0x150f9231, 0x033ead7b, 0x62e123}}}, + /* 7*16^6*G: */ + {{{0x1e99f728, 0x1eaca112, 0x1c48813a, 0x06ebf7cd, 0x05303677, 0x1f93dbb5, 0x1d3ed993, 0x0e951295, 0x247969}}, + {{0x0baaebff, 0x1d0028b7, 0x1d68b60d, 0x17e7812a, 0x1664a5ad, 0x143f3ec6, 0x0007b14b, 0x088d11e6, 0xe3d78d}}}, + /* 9*16^6*G: */ + {{{0x0fb0079a, 0x0f0636a1, 0x04981272, 0x1f3dee47, 0x18324916, 0x0cf73b59, 0x1fc18c69, 0x1b547aab, 0x2f39cb}}, + {{0x0c5690ba, 0x1114b981, 0x0a808c3f, 0x167f7910, 0x1a58b9bf, 0x1b6813c6, 0x060d36a4, 0x1bc270c7, 0xabeadb}}}, + /* 11*16^6*G: */ + {{{0x04f7ab73, 0x09980597, 0x1110e9de, 0x07a9d53a, 0x0aed262e, 0x0f43629a, 0x06e95a8e, 0x0d864fac, 0xe5a31d}}, + {{0x10561f42, 0x089d1fe3, 0x032e884e, 0x18889350, 0x0ce5dbf8, 0x054bbd27, 0x15e83046, 0x07b1a3d3, 0x37788c}}}, + /* 13*16^6*G: */ + {{{0x014dcd86, 0x07c94d1e, 0x0fdc6d62, 0x0ba8412d, 0x1dcf11fc, 0x0ecc1028, 0x111f7d43, 0x0941a2a6, 0xcc389d}}, + {{0x08f0a873, 0x075b6ece, 0x1f9e1d1a, 0x0afc31fc, 0x110ca05c, 0x05eddf54, 0x0fb66d5a, 0x1acc1ed7, 0x93ae4f}}}, + /* 15*16^6*G: */ + {{{0x18819311, 0x07ce375b, 0x01dc51c9, 0x1c3dc421, 0x1ed1f0b3, 0x10bf067a, 0x0408dd42, 0x1913ae3d, 0x7f9291}}, + {{0x0c2eb125, 0x14fcdabd, 0x01a85d2a, 0x15548139, 0x015b6120, 0x0f462292, 0x1bc3d743, 0x020c7d87, 0x9da00d}}} + }, + { + /* 1*16^7*G: */ + {{{0x0e7dd7fa, 0x1299f650, 0x0a4660e6, 0x0f2c246f, 0x0d3b5094, 0x17640961, 0x1e62e97f, 0x1a9277d7, 0xeebfa4}}, + {{0x01de8999, 0x0fea7ed7, 0x047dc4b7, 0x099b874e, 0x0089d9ae, 0x1f6d78bc, 0x03c9a7b9, 0x1472e1de, 0x5d9a8c}}}, + /* 3*16^7*G: */ + {{{0x1b7ceceb, 0x1fb3c7fd, 0x05febc3c, 0x0b3f2711, 0x0681473a, 0x1c0937b7, 0x1140dbfe, 0x04084eda, 0x437a86}}, + {{0x16c181e1, 0x1b1de61a, 0x03e5e09c, 0x041f9fb9, 0x097ff872, 0x1f5b4ce9, 0x0cbda6e3, 0x1427dd58, 0xb916b}}}, + /* 5*16^7*G: */ + {{{0x097f96f2, 0x0c6b94f0, 0x121cd735, 0x046a53a5, 0x0c273358, 0x1f1dcd1e, 0x06f20f2d, 0x027c5491, 0xa9ef9f}}, + {{0x16c04be4, 0x01eaad82, 0x06d1c0b0, 0x1f135eb5, 0x1613db74, 0x170b075d, 0x15f3655b, 0x1cb28ab3, 0xe814cc}}}, + /* 7*16^7*G: */ + {{{0x150cf77e, 0x0055ad09, 0x0a2ac36f, 0x17eae8a9, 0x0064207d, 0x13eb4fd5, 0x16f954e0, 0x083dc3a6, 0x66d805}}, + {{0x00eaa3a6, 0x12fcbd7d, 0x0c6ddb4a, 0x0968756f, 0x013f6944, 0x0a1029ab, 0x0d0b0fc7, 0x1ce65fff, 0x51cfdf}}}, + /* 9*16^7*G: */ + {{{0x07213a5a, 0x1aa43144, 0x17e98ae4, 0x064094f0, 0x0c3c80b7, 0x0450e326, 0x1e8afcd4, 0x1c26ca07, 0x62ac05}}, + {{0x146a9e45, 0x08690e07, 0x1e653bf0, 0x12120302, 0x12579e55, 0x13cf03d4, 0x1b934e57, 0x1e741a34, 0x236fbd}}}, + /* 11*16^7*G: */ + {{{0x07bad12b, 0x187ea4c3, 0x1d9b87b0, 0x0bd401d5, 0x12db385d, 0x09d7ae37, 0x1d6d6fd8, 0x092e4891, 0xca13c4}}, + {{0x1723b0f2, 0x0b4cfa34, 0x095d59a2, 0x0156e223, 0x1a3d6637, 0x1d327556, 0x1f22b057, 0x106c3850, 0x83aa09}}}, + /* 13*16^7*G: */ + {{{0x1c80414e, 0x0d772fca, 0x19b3dff7, 0x1f150c5a, 0x09e4914e, 0x0e27a230, 0x0ba16b04, 0x0034e0a5, 0x1cecb1}}, + {{0x12169a3b, 0x0574a496, 0x1c8c7437, 0x0aafca88, 0x1ad16907, 0x11941af6, 0x13ed396a, 0x0cd2c12f, 0xf34360}}}, + /* 15*16^7*G: */ + {{{0x0ed810a9, 0x07ade462, 0x1c005571, 0x113a7e78, 0x123924f8, 0x0d7af8ef, 0x1e732543, 0x0ea09af1, 0x2a6990}}, + {{0x1a9b4728, 0x1c359c47, 0x105171f3, 0x1a8fd2fd, 0x104fc667, 0x0c34aa7d, 0x1f6b0fb1, 0x136d87bf, 0x54f903}}} + }, + { + /* 1*16^8*G: */ + {{{0x19a48db0, 0x1ebc1ad9, 0x0f00effb, 0x042b4536, 0x1de459f1, 0x08504dbd, 0x059c9e47, 0x1b4d2dce, 0x100f44}}, + {{0x0bc65a09, 0x1deae6b1, 0x14656b03, 0x1e9431fe, 0x10666b7f, 0x19980604, 0x0ddcbb23, 0x06325401, 0xcdd9e1}}}, + /* 3*16^8*G: */ + {{{0x15bc15b4, 0x05cd09a4, 0x168bb9a7, 0x0a051c8c, 0x1ca8d927, 0x0774e76b, 0x1727b616, 0x05ca3dd5, 0x10e90e}}, + {{0x18aa258d, 0x075f304a, 0x0edaa20d, 0x0b12c605, 0x11f754ca, 0x14630b56, 0x0109355e, 0x00701abc, 0xc68a37}}}, + /* 5*16^8*G: */ + {{{0x1fe75269, 0x0e9fe181, 0x0f4cc60b, 0x0f47980a, 0x17dcda37, 0x1c85b8a5, 0x18e115d6, 0x085b4a82, 0xf7422f}}, + {{0x17e49bd5, 0x04c07438, 0x08e63806, 0x07446fe9, 0x035977fb, 0x13ee5cfb, 0x04ff4633, 0x03466261, 0x406c2f}}}, + /* 7*16^8*G: */ + {{{0x15a7175f, 0x09db34b7, 0x073d0a99, 0x11cee3a6, 0x1debbedb, 0x0d2ac16a, 0x13fdca1e, 0x0082fa87, 0x2d8cad}}, + {{0x1b9d592a, 0x19bddc8d, 0x0d797833, 0x08d7fb39, 0x09d377a8, 0x197d3096, 0x0529eec8, 0x10663195, 0xc73f3b}}}, + /* 9*16^8*G: */ + {{{0x14b51045, 0x1a64de1c, 0x07096cf8, 0x0d912de6, 0x0cf73bbc, 0x1ea758f4, 0x1a962b9c, 0x03b7314d, 0x1ecbfd}}, + {{0x02c70026, 0x1d338808, 0x0d908b54, 0x000c8d68, 0x09b38b19, 0x05d8c24d, 0x0e9911f4, 0x06117338, 0x1cf6e2}}}, + /* 11*16^8*G: */ + {{{0x09358533, 0x1d66bb37, 0x1ed2e77d, 0x1267f3a9, 0x12a8c10a, 0x0ad148e9, 0x14a20fa5, 0x18bfcaee, 0x9a0894}}, + {{0x0360ba08, 0x19f0e2ee, 0x00376b7e, 0x0dcb7b77, 0x1c32165a, 0x1eafcaa7, 0x1f0c7e45, 0x18840371, 0xa79883}}}, + /* 13*16^8*G: */ + {{{0x198ef7f6, 0x0a202eb0, 0x01e3e7da, 0x07e7eef4, 0x0aea6592, 0x042939dc, 0x0b8d6f67, 0x093b69fa, 0x664dd8}}, + {{0x1d1eac94, 0x1a4b7f9a, 0x039bb3b9, 0x1a756637, 0x058cffc3, 0x0672ee82, 0x04ca8512, 0x02e2fe4f, 0xad5120}}}, + /* 15*16^8*G: */ + {{{0x03c934b3, 0x060535be, 0x02b8b138, 0x03eb00b6, 0x1a7022b3, 0x0cb34c08, 0x018e08c7, 0x126efa17, 0x82113a}}, + {{0x042c6a0f, 0x1f2f3156, 0x111a00dd, 0x1ef84d34, 0x0c628aa1, 0x16795ad0, 0x19982119, 0x1b5935c6, 0x8da1b8}}} + }, + { + /* 1*16^9*G: */ + {{{0x0534fd2d, 0x04566f37, 0x1cece14b, 0x1f1a88c9, 0x0c017a77, 0x113d2502, 0x146c7724, 0x1c4c58fd, 0xe1031b}}, + {{0x1456a00d, 0x0278c794, 0x073b5e69, 0x05ba833c, 0x1535af29, 0x120bb2cb, 0x0179aeda, 0x12512808, 0x9d7061}}}, + /* 3*16^9*G: */ + {{{0x0f028d83, 0x1cb11d77, 0x1d0e5855, 0x0b24db74, 0x069db619, 0x1f2d0aef, 0x17b1a96a, 0x189c78f0, 0xa7ebf7}}, + {{0x19d0bed1, 0x1201c95c, 0x014e4665, 0x07124e96, 0x0804b47a, 0x039bb822, 0x0b573f67, 0x05f7fc6c, 0x620515}}}, + /* 5*16^9*G: */ + {{{0x07dd5cfa, 0x17072011, 0x02752d6e, 0x138a26fe, 0x146336a8, 0x1529a131, 0x1d307371, 0x11b96049, 0x5b5ca0}}, + {{0x1e48e98c, 0x132537cc, 0x0c9a74f9, 0x00cf995e, 0x09094bfd, 0x18675443, 0x0097a647, 0x1ee1542b, 0x3eccb6}}}, + /* 7*16^9*G: */ + {{{0x03531f82, 0x1ca94719, 0x030b27ca, 0x0264d762, 0x02c29ff5, 0x1f3a44e1, 0x0ed733bc, 0x15982229, 0x46f26}}, + {{0x0bceda07, 0x082fe458, 0x0d571fe9, 0x0b28b9b5, 0x12579d02, 0x185617e1, 0x0bab388d, 0x062c6b70, 0x6b804b}}}, + /* 9*16^9*G: */ + {{{0x10432711, 0x058aa1b8, 0x045ae418, 0x08165fbb, 0x1645acf1, 0x1787844c, 0x1ed4d7e5, 0x1b263c1d, 0xc11926}}, + {{0x0fe2610c, 0x04930f17, 0x1cd01579, 0x17245941, 0x0c6cf83a, 0x05f8c366, 0x1a246125, 0x198fa4b6, 0x8be1f8}}}, + /* 11*16^9*G: */ + {{{0x01257963, 0x0bcc3a7d, 0x12aa1870, 0x031aa586, 0x179c45b0, 0x1aa5a9c4, 0x1cb9b36e, 0x1d3d6d11, 0x690846}}, + {{0x066f9835, 0x12bb2cca, 0x124ac94e, 0x18795043, 0x1bb7f6cb, 0x18127c97, 0x0f16d005, 0x196fe7fd, 0xe2485f}}}, + /* 13*16^9*G: */ + {{{0x1ee23ace, 0x0889ca5e, 0x1374bf4b, 0x10f8cb6a, 0x12915dec, 0x0a96fa51, 0x02eaee9d, 0x1f719244, 0xfb3df7}}, + {{0x1722e8de, 0x04ef7a64, 0x149fd7b8, 0x04e285fd, 0x0b58a9e7, 0x08aa06dd, 0x11594a89, 0x178238e7, 0x510e29}}}, + /* 15*16^9*G: */ + {{{0x10272351, 0x103e7f7a, 0x07fc4261, 0x06967bf3, 0x1cd41707, 0x11f59d58, 0x062cfae2, 0x1849eb8a, 0x6dd85e}}, + {{0x1fc7664b, 0x183fd15b, 0x18205f26, 0x18dfef87, 0x041b7877, 0x03fcd7ae, 0x09f82750, 0x1e8243e8, 0x16ea67}}} + }, + { + /* 1*16^10*G: */ + {{{0x1094696d, 0x0af3446c, 0x075abd4b, 0x1164cd48, 0x1d7ec5cf, 0x01cf8a1d, 0x0d4c2b0a, 0x15c8daab, 0xfeea6c}}, + {{0x18090088, 0x0aaef5f8, 0x10510b4c, 0x1912af98, 0x0cd5c981, 0x07095f9f, 0x06eac1b9, 0x0d92fb9c, 0xe57c6b}}}, + /* 3*16^10*G: */ + {{{0x08dfd587, 0x1c9b0dda, 0x0c099581, 0x09747193, 0x1a12d5ec, 0x1d55167a, 0x022cd219, 0x03759e8a, 0x5084b4}}, + {{0x11470e89, 0x13cf4bfc, 0x047d581b, 0x0deac0d1, 0x127475db, 0x13642a94, 0x14c5866a, 0x0343b301, 0x34a963}}}, + /* 5*16^10*G: */ + {{{0x1ab34cc6, 0x0411930b, 0x1cc284b4, 0x1852ecf9, 0x17128c80, 0x1f8fe8c6, 0x17a94fec, 0x07c0c85a, 0x4f14c0}}, + {{0x187e681f, 0x0f61297c, 0x00774089, 0x1c799d1d, 0x02540b9d, 0x1387a1d3, 0x0253194e, 0x1519549d, 0x7b53d0}}}, + /* 7*16^10*G: */ + {{{0x1241d90d, 0x013b8808, 0x09113e0d, 0x19e283b6, 0x1d363e81, 0x1b04af6e, 0x1b475050, 0x0fc938f3, 0xa74db8}}, + {{0x1f7adad4, 0x1928c5c1, 0x0828c4fc, 0x1ca12689, 0x171c8a9e, 0x08452c40, 0x1bcc9ff7, 0x19b5e47d, 0xf78691}}}, + /* 9*16^10*G: */ + {{{0x11c1ae1f, 0x0f665111, 0x13502ca9, 0x1cb18d15, 0x15658456, 0x06a275d1, 0x0b3e6b37, 0x0ae89754, 0x6901fa}}, + {{0x122838b0, 0x1c19832e, 0x11dea4c3, 0x1e774bcb, 0x0900dd79, 0x09c0614e, 0x0849186d, 0x11044e78, 0x35de5c}}}, + /* 11*16^10*G: */ + {{{0x127a4bdb, 0x1818840d, 0x12532b12, 0x14da086a, 0x1a35d046, 0x1b21f8dd, 0x049e8912, 0x05a3a870, 0x8d3cd8}}, + {{0x069a8a2c, 0x1e9a63e7, 0x02b4a5b0, 0x0700fa6e, 0x0236ed4e, 0x1fce803b, 0x07d1c33e, 0x0c301dc8, 0x9bd425}}}, + /* 13*16^10*G: */ + {{{0x14ec1d2d, 0x00669e35, 0x1f63d151, 0x133eb8dc, 0x1691fd90, 0x0b394b3d, 0x1ce6bfa7, 0x0c7ac0c8, 0xeaf983}}, + {{0x0c838452, 0x07f3ab02, 0x1a12d4ff, 0x0a5aa8af, 0x199aaa9f, 0x14507358, 0x1489dd48, 0x074ffcf1, 0xe51818}}}, + /* 15*16^10*G: */ + {{{0x045ae767, 0x059adfb8, 0x025dc72f, 0x0753973d, 0x0e5d8c27, 0x07029603, 0x18d19bd0, 0x02c75db6, 0xfb95bd}}, + {{0x1bbf0e11, 0x029f5057, 0x167c4d06, 0x0de8e314, 0x0275bb81, 0x06ce9b41, 0x16f14801, 0x1b02351b, 0x664c14}}} + }, + { + /* 1*16^11*G: */ + {{{0x01ec6cb1, 0x1fd4bc5e, 0x0160f78c, 0x1acafb01, 0x1ca3cfee, 0x1f25f37f, 0x1372cd9e, 0x03b22093, 0xda67a9}}, + {{0x1a68be1d, 0x14f54713, 0x1dd0285f, 0x0f5b8a11, 0x180e5dec, 0x11fbf64b, 0x0af107d1, 0x06a902c8, 0x9bacaa}}}, + /* 3*16^11*G: */ + {{{0x15bc8a44, 0x17ee8328, 0x18546867, 0x0202ef97, 0x05fc7684, 0x12d25d2d, 0x168f4e15, 0x0b079f9d, 0x4d0180}}, + {{0x1adbc09e, 0x18fca648, 0x00b68d8b, 0x08408d0b, 0x03813969, 0x1d4003eb, 0x174d9fa6, 0x1831969e, 0x3a33c6}}}, + /* 5*16^11*G: */ + {{{0x05daeb00, 0x00d5a943, 0x1917ddaf, 0x07d6499c, 0x0e9d1592, 0x1b5139db, 0x055c20b2, 0x00fbeb9f, 0x2f6615}}, + {{0x033992c0, 0x113b3c4c, 0x174c2304, 0x1bdc4e32, 0x0add06ec, 0x09bd4100, 0x0cfdbbe5, 0x026dea56, 0xfd5c12}}}, + /* 7*16^11*G: */ + {{{0x116aa6d9, 0x01548504, 0x1c0b73c6, 0x05916c8e, 0x15a38366, 0x0ba6d0c1, 0x1f48953c, 0x0fa0bfc8, 0xf59411}}, + {{0x1f2e50cf, 0x1e834b75, 0x1ad6e1b1, 0x04ef107c, 0x0bceb7a9, 0x0ded584a, 0x0c4b3d97, 0x14add2e3, 0xcaa761}}}, + /* 9*16^11*G: */ + {{{0x1ac6f4c0, 0x15701cab, 0x12f71332, 0x1d1bd198, 0x0711dda4, 0x01c5f34b, 0x137b1387, 0x0fe3e9b3, 0xf2d4d}}, + {{0x12339b58, 0x1f3ddd6b, 0x090995b9, 0x14214f20, 0x1e71e8f6, 0x13fef9c0, 0x19345fec, 0x10afd27b, 0x3ec89f}}}, + /* 11*16^11*G: */ + {{{0x1f428cb2, 0x02a829fe, 0x088ad576, 0x1045facd, 0x0d0f1233, 0x10c0acac, 0x0ef47ade, 0x185c5429, 0x1d5dce}}, + {{0x095b189b, 0x12f68804, 0x18112947, 0x1d225f0e, 0x10b88bd3, 0x03c12437, 0x0314341e, 0x10762859, 0x6e5c40}}}, + /* 13*16^11*G: */ + {{{0x08381273, 0x1875447d, 0x04f6b97e, 0x06ed2c0d, 0x126ced84, 0x14d96620, 0x1d0e7f7a, 0x1fa6012c, 0x89d9a2}}, + {{0x1309773d, 0x01f59f76, 0x049cc928, 0x03ad015a, 0x162f58f6, 0x17903b67, 0x1d40ddea, 0x168a3acd, 0xdfca25}}}, + /* 15*16^11*G: */ + {{{0x15c71d91, 0x06195965, 0x0253f487, 0x08bc5c55, 0x0fece239, 0x0e0988ad, 0x0b8714a8, 0x10f074a1, 0x83191b}}, + {{0x02148a61, 0x05cf6047, 0x01117b9c, 0x023ea2ea, 0x0ae8a17a, 0x0f09e8be, 0x0dc2781b, 0x02ae7003, 0xe0ac7f}}} + }, + { + /* 1*16^12*G: */ + {{{0x1a37b7c0, 0x1aa2e660, 0x0441a7d5, 0x11a1ef76, 0x02151ec0, 0x0049af79, 0x13769b80, 0x15416669, 0x53904f}}, + {{0x022771c8, 0x0e584b58, 0x110d1a67, 0x133303c2, 0x13c1c139, 0x16656106, 0x01b62327, 0x1a179002, 0x5bc087}}}, + /* 3*16^12*G: */ + {{{0x08a2050e, 0x0d6217f2, 0x17e299dc, 0x1deaaec2, 0x19b89742, 0x14e63723, 0x0c625add, 0x1fa4978e, 0x673724}}, + {{0x061d3d70, 0x0864d248, 0x0d2730ae, 0x1759fa86, 0x06b6dbe6, 0x01604d44, 0x088080d2, 0x0af12d49, 0xe4cf82}}}, + /* 5*16^12*G: */ + {{{0x02de63bf, 0x1fb7241c, 0x098719b2, 0x15ea650e, 0x166a8e03, 0x05318fb0, 0x10c27966, 0x148e5be9, 0x4366ef}}, + {{0x017924cd, 0x16352047, 0x0a9b5ac0, 0x1618a4b5, 0x068eaf33, 0x09bf0981, 0x1f38bb89, 0x0137dc5a, 0x2e7dd9}}}, + /* 7*16^12*G: */ + {{{0x06f96190, 0x08293ff8, 0x125497bc, 0x005bd20f, 0x0a75fd1f, 0x0ab4b33d, 0x0c7e5ef9, 0x0c4f3235, 0x7bd753}}, + {{0x0bda00f6, 0x1e8b9025, 0x03a9a568, 0x1f98b83c, 0x027d6ce0, 0x123a4a1c, 0x0c2757b5, 0x167b774c, 0x8336f2}}}, + /* 9*16^12*G: */ + {{{0x16ad41ed, 0x1d8a98aa, 0x1c0d490c, 0x11586be9, 0x0dc92030, 0x00cf448c, 0x1706be8d, 0x0f7bb55a, 0x4f7e92}}, + {{0x1e642d57, 0x1a1abc33, 0x0bddd6f7, 0x0628e29d, 0x0f6a62e7, 0x006fa9d4, 0x0c4154a6, 0x0a2ad511, 0xdfe774}}}, + /* 11*16^12*G: */ + {{{0x07748690, 0x1d302893, 0x18c2c073, 0x0f209bb0, 0x13d007d5, 0x0958f6e9, 0x133252d1, 0x10cfa523, 0x2355cb}}, + {{0x0c89582b, 0x1e23a98a, 0x0724e451, 0x10d0b19a, 0x07c58582, 0x02f60ad5, 0x07e3d56e, 0x114b4e3c, 0x21c2f1}}}, + /* 13*16^12*G: */ + {{{0x0ade7f16, 0x0d7510b0, 0x0f80a31b, 0x1975d279, 0x15d24ae9, 0x0955b613, 0x15b004d6, 0x0b7367b4, 0xb6682}}, + {{0x08c56217, 0x0a221342, 0x19f34af6, 0x08781be7, 0x1a97fb72, 0x1b5d45ab, 0x0cffbce9, 0x17031c13, 0xa1fba0}}}, + /* 15*16^12*G: */ + {{{0x19060d5b, 0x08358114, 0x0e8e9f0a, 0x0c276238, 0x151cb904, 0x0d97ecfc, 0x08b2d842, 0x079e17a0, 0xf60204}}, + {{0x1af88f13, 0x17b7a858, 0x17468fdd, 0x14ada56f, 0x17bea37a, 0x07b25627, 0x1c66206a, 0x00d83e19, 0xf036b7}}} + }, + { + /* 1*16^13*G: */ + {{{0x1ad86047, 0x1fcacfa1, 0x06e2f2bb, 0x0a740875, 0x0906779b, 0x053bb265, 0x0e9dc673, 0x017a6b30, 0x8e7bcd}}, + {{0x0460372a, 0x108023f4, 0x1f5a2cfa, 0x111c5c8f, 0x1514579e, 0x08210654, 0x12ce500c, 0x016547b4, 0x10b777}}}, + /* 3*16^13*G: */ + {{{0x041ead4b, 0x1f443cd0, 0x06c0f07f, 0x0bdbf6d2, 0x076be3a7, 0x19a77d7f, 0x0dfb1c51, 0x019191e6, 0xbfc90c}}, + {{0x06fedaed, 0x02963784, 0x182b8f9d, 0x0d1dfe65, 0x02d36fb4, 0x18c6ea82, 0x1b4936e9, 0x163c139b, 0x7a9481}}}, + /* 5*16^13*G: */ + {{{0x15bb3b3e, 0x173de83b, 0x07dcf2c9, 0x0a6c2fdf, 0x13f5b507, 0x0c9f4616, 0x0a937296, 0x0397c7f5, 0x732df1}}, + {{0x17366693, 0x02bbf0f6, 0x11610db3, 0x1b5adac9, 0x13916e69, 0x12ac2012, 0x05df2df8, 0x07dbd1f3, 0x7f4190}}}, + /* 7*16^13*G: */ + {{{0x088dc3b9, 0x0fad9e0c, 0x1dd32671, 0x0cd249d2, 0x1ef6019a, 0x0420664b, 0x1ed0a36a, 0x172c0728, 0x4ce094}}, + {{0x05c0de52, 0x00a7bdb7, 0x1a81940b, 0x00b64193, 0x0aca2162, 0x06c0653b, 0x0cfb55ed, 0x1757e353, 0x5390f}}}, + /* 9*16^13*G: */ + {{{0x0aaafe5a, 0x01baf058, 0x026bb753, 0x08e1674a, 0x03fd0e25, 0x1354ad81, 0x1f7a5b62, 0x16edf8cc, 0x9a968e}}, + {{0x0ed975c0, 0x135fea12, 0x19c33033, 0x0b1014cb, 0x01d0ee7b, 0x13681ec3, 0x08a553f1, 0x00f4da77, 0xabf6fb}}}, + /* 11*16^13*G: */ + {{{0x134c6397, 0x1a8e5fcf, 0x1d33424d, 0x1a7b6a00, 0x0b22107d, 0x17c0129b, 0x06553c2b, 0x1da02e2c, 0xd3c6fb}}, + {{0x08cb3f9c, 0x0fe4682b, 0x1783802c, 0x18ee1120, 0x0b6468a0, 0x1ca6c975, 0x0bc65160, 0x18abcbc5, 0x4a0dd2}}}, + /* 13*16^13*G: */ + {{{0x0ac3137e, 0x0dc12c98, 0x0bd91186, 0x04b6c54b, 0x13953fe9, 0x0353b555, 0x0ee380bc, 0x13025248, 0x4cbde3}}, + {{0x0ec02fe6, 0x00478ae7, 0x03ab5830, 0x074f5cb1, 0x0c370d19, 0x1509a5ca, 0x05654024, 0x0c11e26c, 0x6ce554}}}, + /* 15*16^13*G: */ + {{{0x00fbf84b, 0x1d118367, 0x0fc2e291, 0x091f9778, 0x0cebb03c, 0x0e39860a, 0x091ee2f6, 0x0790562c, 0x4b9d33}}, + {{0x036c3c48, 0x1cf725a5, 0x1d6d7988, 0x0daa87c5, 0x1b7eb676, 0x1ecc133c, 0x054954c4, 0x1f7c4998, 0xfd7fc7}}} + }, + { + /* 1*16^14*G: */ + {{{0x19c43862, 0x1420f0ac, 0x05f99a42, 0x0fe9e307, 0x01bde71a, 0x00c344dc, 0x1c879b42, 0x069839bf, 0x385eed}}, + {{0x142e5453, 0x022c7f2a, 0x01b72330, 0x009dd841, 0x1f4576b3, 0x0f0cf4f5, 0x0fd59c07, 0x187d1d44, 0x283beb}}}, + /* 3*16^14*G: */ + {{{0x16e2d9b3, 0x05e98355, 0x0e358d45, 0x17250636, 0x1845641d, 0x15309ce7, 0x179d784b, 0x1e72f8e0, 0x19a314}}, + {{0x0baaaf33, 0x0a97712e, 0x012f95b5, 0x043a3a48, 0x128b3a50, 0x12fc43fa, 0x03748d25, 0x1ebb58e5, 0x6cacd8}}}, + /* 5*16^14*G: */ + {{{0x12f00480, 0x0c2c3f58, 0x00373b9f, 0x0b100942, 0x07219203, 0x0c31b27b, 0x0a8d5772, 0x0972b51b, 0x5840ed}}, + {{0x1e22cf9e, 0x0c96af15, 0x0b8e1c85, 0x0a44a8a5, 0x1d8daba7, 0x06f550ae, 0x05041e5a, 0x0d64417e, 0x670cda}}}, + /* 7*16^14*G: */ + {{{0x03f54c42, 0x0426f741, 0x068f7239, 0x1834784d, 0x0532545d, 0x060fa767, 0x03ec7716, 0x14a68d23, 0x9f5701}}, + {{0x0feb6a21, 0x1070e249, 0x067949e1, 0x1cf09564, 0x1bfdd89e, 0x0db5ab94, 0x195efee5, 0x171003b3, 0xce7b8f}}}, + /* 9*16^14*G: */ + {{{0x1522461a, 0x14a09994, 0x11c60c9f, 0x06144cb7, 0x0f9a0bcb, 0x0380833f, 0x13f006ee, 0x0d246b51, 0x27f611}}, + {{0x07301a2d, 0x152657ce, 0x018e511a, 0x103641b5, 0x08ee8e49, 0x02b093a1, 0x0b4ba923, 0x1532014d, 0xe512f1}}}, + /* 11*16^14*G: */ + {{{0x114f36b9, 0x07164d96, 0x0e7ce433, 0x119576c7, 0x0a981259, 0x197a1afa, 0x0504986f, 0x10ad9ddf, 0x640779}}, + {{0x04b4b50a, 0x0a58f74f, 0x073baca2, 0x1410e093, 0x07b6c8cd, 0x0bafec2d, 0x1bebbe43, 0x11e89cad, 0xda6192}}}, + /* 13*16^14*G: */ + {{{0x14d6b76f, 0x17b1efcc, 0x120576f3, 0x0b53f769, 0x1feae7fe, 0x1845e04e, 0x1a7d14bd, 0x1c6390ac, 0xa23750}}, + {{0x0dcca8da, 0x0ec96664, 0x0e123450, 0x00f823fb, 0x11113e77, 0x1d1f26a0, 0x19b6b0cb, 0x0294dcfb, 0xf7339b}}}, + /* 15*16^14*G: */ + {{{0x1ceee475, 0x1774e327, 0x1b5e0ac4, 0x15905081, 0x0ff41ab6, 0x0010f9e5, 0x1e357b4f, 0x00f47e46, 0xbbf1ac}}, + {{0x07fe5067, 0x03115004, 0x02d075a1, 0x173b1287, 0x15fe324e, 0x1e641b58, 0x03984220, 0x1bdd5a8c, 0xb4bfb8}}} + }, + { + /* 1*16^15*G: */ + {{{0x03fac3a7, 0x10376c36, 0x11fef271, 0x1bf094b2, 0x1fa180fd, 0x19d2209e, 0x06458df1, 0x17007d9e, 0x6f9d9}}, + {{0x1a842160, 0x03448301, 0x0a0400b6, 0x09ba5eb8, 0x1c4d47ea, 0x11518722, 0x06e9a6e3, 0x11cc060b, 0x7c80c6}}}, + /* 3*16^15*G: */ + {{{0x121ce204, 0x076baf46, 0x19d8f549, 0x0e4b1c84, 0x0f72fb2a, 0x06c2ce53, 0x193ee0dd, 0x1a2c5678, 0x43ca41}}, + {{0x134a8f6b, 0x09282274, 0x09291a39, 0x0d8f667d, 0x1a31f9ab, 0x07c90c6d, 0x0fe87194, 0x105c6e04, 0xdcea5a}}}, + /* 5*16^15*G: */ + {{{0x0be6efda, 0x07e74967, 0x1ca01659, 0x1a9fe7f0, 0x0506d922, 0x1b91bc2d, 0x0fd6d99b, 0x1de45125, 0x9c3e06}}, + {{0x07aefc7d, 0x18a07995, 0x0dbf7df7, 0x1790d0f6, 0x06fd5d43, 0x196a2671, 0x08f62bc2, 0x1cbcec52, 0xa7b709}}}, + /* 7*16^15*G: */ + {{{0x06c88be2, 0x0893d5ae, 0x1bb9789e, 0x18f041a0, 0x0775bea2, 0x13acec18, 0x1c0ceedc, 0x14627c41, 0x5d6f8a}}, + {{0x0d7ad75d, 0x0972a9f8, 0x0fe4b0a2, 0x16df1d4d, 0x0bc20eda, 0x1799d584, 0x13a31c6a, 0x11b1aada, 0xadc4b1}}}, + /* 9*16^15*G: */ + {{{0x12d1b844, 0x1449a8dc, 0x1cf9213c, 0x18070582, 0x08bc5c69, 0x0ae1e09c, 0x157f21ac, 0x186094c1, 0xf57d35}}, + {{0x01266837, 0x125d5deb, 0x04571a91, 0x0d2e4061, 0x0634c700, 0x09fad4f2, 0x1365e413, 0x13d531de, 0x707f3d}}}, + /* 11*16^15*G: */ + {{{0x1cc7cb09, 0x1a6803f9, 0x146d0d48, 0x0fd6d143, 0x071463bc, 0x10ff71ec, 0x1297d65b, 0x0f474cb2, 0x13e760}}, + {{0x08079160, 0x1f3ad450, 0x0d5d9046, 0x15c576cd, 0x0299d65e, 0x1eec2d9a, 0x02c78c97, 0x11bd1f77, 0x284dc8}}}, + /* 13*16^15*G: */ + {{{0x18cdee05, 0x03067092, 0x0bb0ee40, 0x0c3f642e, 0x0901da87, 0x12858d83, 0x0b989000, 0x044ad030, 0x29bea3}}, + {{0x062651c8, 0x12501acd, 0x11a638e7, 0x18636d91, 0x05ec7f9f, 0x0d9fdc38, 0x083aa402, 0x144d21d3, 0x7c40d9}}}, + /* 15*16^15*G: */ + {{{0x12f18ada, 0x0db63ab0, 0x16f6f304, 0x017b2777, 0x14a59d46, 0x17d7f99e, 0x039f670d, 0x0da47051, 0xf52178}}, + {{0x03953516, 0x0eb457e9, 0x16fc2607, 0x1de946d8, 0x1d1d6aa5, 0x10815e68, 0x0d5fb309, 0x17ec071b, 0xe0686f}}} + }, + { + /* 1*16^16*G: */ + {{{0x02d0e6bd, 0x1dbf073a, 0x03d794c4, 0x09a2c7b6, 0x16ecbf77, 0x0a3e0826, 0x18960a88, 0x00248789, 0x3322d4}}, + {{0x0c28b2a0, 0x079d174b, 0x01cebd89, 0x0bec7d45, 0x0f9b7280, 0x0cde26ed, 0x1bd6fec0, 0x12fd2cc9, 0x56e707}}}, + /* 3*16^16*G: */ + {{{0x059ab499, 0x1ece9f90, 0x1cf0cc2a, 0x065338dc, 0x101bc0b1, 0x0b59e33f, 0x16e97486, 0x1e602b80, 0x78baaf}}, + {{0x1ee097fd, 0x00e918c7, 0x0494665a, 0x065ddd1a, 0x0082e916, 0x027076c1, 0x02bebf2a, 0x1b7b60d8, 0xad4bdc}}}, + /* 5*16^16*G: */ + {{{0x1d06ace6, 0x049f0b67, 0x0e883291, 0x01366df0, 0x1ab1a237, 0x024c2494, 0x0f53082e, 0x0234295c, 0x6f70f2}}, + {{0x1602d5de, 0x045f69a5, 0x16b17b81, 0x052acd7c, 0x19f50753, 0x0c79a3dc, 0x0dcdbe57, 0x0612804f, 0x791e8a}}}, + /* 7*16^16*G: */ + {{{0x00ee1b40, 0x04771f73, 0x1a5891f7, 0x1a90b6e3, 0x1ccd48ce, 0x04f8c881, 0x1057e025, 0x1653ad54, 0xe1599d}}, + {{0x178f93a6, 0x0eb132f6, 0x0ca66778, 0x0c74e978, 0x1c7cfa63, 0x04a55517, 0x1283bebe, 0x0465503a, 0x793362}}}, + /* 9*16^16*G: */ + {{{0x09c00c3e, 0x00efd142, 0x048238be, 0x1d1e0792, 0x11859f00, 0x11699ea2, 0x05590d95, 0x12e0880d, 0xbb0b04}}, + {{0x11955a35, 0x0cd4c168, 0x1772429e, 0x0e089d20, 0x1b052fe6, 0x17d0bd58, 0x1d8d9574, 0x0b0a75f3, 0x4067e4}}}, + /* 11*16^16*G: */ + {{{0x05dd32e6, 0x073adce0, 0x0f97b9f8, 0x076aa36a, 0x05fbfc66, 0x0edf03ad, 0x027a6d92, 0x0aa832af, 0xdc5a41}}, + {{0x154a99b9, 0x073edbd3, 0x1926f3e0, 0x05dd20ed, 0x159442ff, 0x12f100df, 0x1e9db73a, 0x14c7f3ec, 0x4af3a8}}}, + /* 13*16^16*G: */ + {{{0x0544e7cb, 0x16a2dd62, 0x0a580d67, 0x0c844b6a, 0x14e99a10, 0x0a52b880, 0x0e76f8cd, 0x0e0730e7, 0x156e19}}, + {{0x0d250a37, 0x0a9c9605, 0x0d0e735b, 0x0dab1abd, 0x14be8949, 0x0b9531c1, 0x01f6a4e5, 0x13f1e632, 0x6bc08d}}}, + /* 15*16^16*G: */ + {{{0x059853ca, 0x1fde14e6, 0x066fd536, 0x12c4d73e, 0x1161348e, 0x1b511473, 0x0e09af29, 0x19d96d08, 0x4269bc}}, + {{0x15b8d367, 0x14ac77a9, 0x196a28f6, 0x12814bf3, 0x1a409fd3, 0x0654e218, 0x1adc8f21, 0x03505802, 0xed2b1c}}} + }, + { + /* 1*16^17*G: */ + {{{0x0134ab83, 0x10eba694, 0x190ce5dc, 0x167f35ee, 0x05868741, 0x1b86c4b3, 0x1f68af45, 0x0fa5bc16, 0x85672c}}, + {{0x190313a6, 0x07184a7b, 0x0a63d132, 0x1e2ff98a, 0x0c2e5e77, 0x024dfd31, 0x0bad8dd0, 0x136b6876, 0x7c481b}}}, + /* 3*16^17*G: */ + {{{0x03ba9000, 0x0f8391d4, 0x097a2dbf, 0x0e5f38d0, 0x0143dc48, 0x1b03ac20, 0x0305a121, 0x1f3ffe3b, 0xac3874}}, + {{0x0f10cf0a, 0x0d1e3ecb, 0x19ba7e93, 0x1c6a1afe, 0x17f93085, 0x0ef44a08, 0x01a6e18b, 0x04611438, 0xaa65e9}}}, + /* 5*16^17*G: */ + {{{0x0d06dbd4, 0x13037b37, 0x08834206, 0x1c7f0af1, 0x1e729ec0, 0x003af4d1, 0x004e6b45, 0x1cf54d0e, 0x570d5c}}, + {{0x1d1ed495, 0x132df675, 0x1182fb56, 0x0746db8c, 0x01bbbb68, 0x173388e8, 0x0bd816d9, 0x092841c0, 0xa6ae53}}}, + /* 7*16^17*G: */ + {{{0x092d230e, 0x1a60fc90, 0x04ce4a10, 0x1c6541a5, 0x06ef5dae, 0x114f701b, 0x0edbe1f0, 0x0e0504d1, 0x75b5f8}}, + {{0x151570b8, 0x1be5efde, 0x047e3ec0, 0x0f49600a, 0x1fa8e026, 0x03a2aa6e, 0x148d8f5e, 0x043c74f0, 0x527cce}}}, + /* 9*16^17*G: */ + {{{0x034fcc0e, 0x1db5fb56, 0x18e21311, 0x1e214857, 0x059c8927, 0x1c0713e9, 0x1b0ac296, 0x1f5c3dbb, 0x44fc8e}}, + {{0x119c420a, 0x07f818f3, 0x14122767, 0x1d294979, 0x1d3d7720, 0x13f3c419, 0x0d9f9249, 0x12975362, 0xd2c7de}}}, + /* 11*16^17*G: */ + {{{0x0bb69991, 0x0d240fe4, 0x0c1c5d75, 0x167f4586, 0x0f535fff, 0x0b310701, 0x0f1a19a8, 0x08f759cf, 0xdea2ba}}, + {{0x116fe2df, 0x033a154f, 0x07b66f1c, 0x1b9b66c4, 0x1b9e7229, 0x1ff6427b, 0x0392b172, 0x1adb2185, 0xae28bf}}}, + /* 13*16^17*G: */ + {{{0x114fc9cc, 0x01206812, 0x09185963, 0x00157853, 0x0a83626d, 0x07b6625c, 0x035bbf07, 0x1314dc2d, 0x3968fc}}, + {{0x1fad37dd, 0x0c9ca44a, 0x023ccd00, 0x08caedff, 0x132c91a1, 0x0c168d56, 0x04a048de, 0x1a1b696b, 0x789cbb}}}, + /* 15*16^17*G: */ + {{{0x0e0c85f1, 0x17610c8d, 0x0e8e8942, 0x0a5ca6c0, 0x145d5a6a, 0x0ef84abc, 0x08a49ac9, 0x00d31c0d, 0x689691}}, + {{0x0dc1de21, 0x03a41199, 0x1540e48b, 0x01833b41, 0x1d72d1f4, 0x02e0ec22, 0x1e495bcc, 0x16967192, 0xaefd3f}}} + }, + { + /* 1*16^18*G: */ + {{{0x00c82a0a, 0x1ecacd7b, 0x19a20cbf, 0x044d8c1e, 0x013b10f9, 0x04f8c8ca, 0x0291ac1b, 0x10136331, 0x948bf}}, + {{0x18c8e589, 0x065bfc46, 0x1f34afb5, 0x1bfe1192, 0x1418c6d4, 0x1a62e8e1, 0x191b71ad, 0x10adb96c, 0x53a562}}}, + /* 3*16^18*G: */ + {{{0x18c8ac7f, 0x1417f2fd, 0x18aa949c, 0x0485dccb, 0x0f849641, 0x1cb6902b, 0x0ef2d70c, 0x1f7c7045, 0x9945b2}}, + {{0x09aea3b0, 0x16ca1d0b, 0x16b37ea5, 0x1ef447dd, 0x0eff5282, 0x1a27fd94, 0x00b581f6, 0x104961e5, 0x3eefed}}}, + /* 5*16^18*G: */ + {{{0x169e353a, 0x08ebcf1c, 0x0ef87dbb, 0x008810a5, 0x1d5fe10a, 0x01113883, 0x03988d7e, 0x0d640b0e, 0x2a314c}}, + {{0x05746067, 0x12c9370f, 0x09962ff0, 0x14a955b6, 0x01ba0138, 0x1f23b5d5, 0x1eb06918, 0x017e6b44, 0x15a4ac}}}, + /* 7*16^18*G: */ + {{{0x09b84966, 0x0f17a4f7, 0x1fcffe62, 0x1e820dba, 0x16c911b4, 0x17d79d35, 0x10b5262d, 0x0016e07f, 0x5959a5}}, + {{0x07473a6a, 0x0533190c, 0x1f890990, 0x01b98119, 0x02a70910, 0x094106e4, 0x025fe50c, 0x0e83eb95, 0x370e6}}}, + /* 9*16^18*G: */ + {{{0x0bc6b173, 0x1864dc91, 0x1b4fface, 0x10c478fd, 0x15f9d7dd, 0x0623182d, 0x1fa38458, 0x0726e445, 0x9eeb31}}, + {{0x1723a71d, 0x09cb106c, 0x19c312e5, 0x0e357da1, 0x01ae30ea, 0x15fedddd, 0x163654aa, 0x1c0221da, 0xe121f1}}}, + /* 11*16^18*G: */ + {{{0x1ec805f3, 0x1b9221fb, 0x16656455, 0x081eea13, 0x097887de, 0x191c4037, 0x03d45bae, 0x1c98fee3, 0x39cc4f}}, + {{0x1a3c48d3, 0x0c8d0609, 0x1244b934, 0x12ae6e7f, 0x0de7dbbb, 0x1349e7a1, 0x03cc5479, 0x058b48df, 0xecb147}}}, + /* 13*16^18*G: */ + {{{0x0e22580e, 0x1eb17dae, 0x15be21e4, 0x06512da5, 0x1d4d2c71, 0x1fef326d, 0x11a5a24b, 0x0e8cdd9b, 0xf94c80}}, + {{0x1127db82, 0x0f291fb3, 0x0dc753a0, 0x0fd88a64, 0x081f6988, 0x1ffb55ad, 0x096a4652, 0x1b8cf0a4, 0x5e9c7f}}}, + /* 15*16^18*G: */ + {{{0x10c4f21f, 0x1f205d68, 0x00f69e9a, 0x0952b29a, 0x199d2502, 0x10346d8c, 0x058bf300, 0x0d8d5aba, 0x8cccb8}}, + {{0x129dfea0, 0x1f893753, 0x192f8a3d, 0x05b95904, 0x158a54b9, 0x17aa4e43, 0x110da66f, 0x0b0c4ea3, 0x57f896}}} + }, + { + /* 1*16^19*G: */ + {{{0x138fd8e8, 0x0766c0cf, 0x1a5d4ab3, 0x01c89bf8, 0x073a8f1b, 0x1e707814, 0x070d3c19, 0x0fe8c300, 0x6260ce}}, + {{0x12b4ae17, 0x0d4274ad, 0x14706630, 0x05244700, 0x01ef7ecd, 0x0824bbb5, 0x15c69fc2, 0x056df4b6, 0xbc2da8}}}, + /* 3*16^19*G: */ + {{{0x01136602, 0x185d232a, 0x078e96ee, 0x08de901b, 0x13b3d38c, 0x049bf919, 0x1f0cf416, 0x0500905b, 0x87d127}}, + {{0x18af6aac, 0x1b41e20e, 0x14efdf13, 0x1108e8df, 0x1745387a, 0x13b67fb3, 0x0f7a49a8, 0x10e14b40, 0x71ce24}}}, + /* 5*16^19*G: */ + {{{0x08c5a916, 0x1902eb9a, 0x15843c96, 0x18881aa6, 0x14aa13f5, 0x0631ed5a, 0x05d1ac2b, 0x07fc4c3d, 0xfd5d7d}}, + {{0x1adb8bda, 0x0a59bd83, 0x13dbeaac, 0x0e70297b, 0x1b52fe5d, 0x1e533ce3, 0x0c1f4ad0, 0x1a1dd6ab, 0xdd83e}}}, + /* 7*16^19*G: */ + {{{0x15f7529c, 0x0ecc84b1, 0x0f547751, 0x0cb7316b, 0x04381387, 0x09e1969a, 0x1848ae91, 0x02130384, 0xde0dd4}}, + {{0x04cd88fe, 0x1e106017, 0x06ddd018, 0x12498d11, 0x03570178, 0x04c116bd, 0x117e6c84, 0x13a21442, 0xd70a6e}}}, + /* 9*16^19*G: */ + {{{0x18f76d11, 0x0417a469, 0x014555cf, 0x02001f7f, 0x092a2151, 0x1f7e1ce1, 0x1139a716, 0x115b499e, 0xb26c20}}, + {{0x03b7356b, 0x00e0058f, 0x009892f7, 0x0060cb3b, 0x16433050, 0x143ec866, 0x0cf3c313, 0x1041293a, 0x1f1cf8}}}, + /* 11*16^19*G: */ + {{{0x069e22db, 0x0a71d833, 0x07224cfe, 0x127feb3f, 0x0294eac9, 0x1e9480c6, 0x148e9f8e, 0x171f8ffe, 0xfceb14}}, + {{0x1c2260a1, 0x1ab96d92, 0x13af932f, 0x0a1cf274, 0x10924ad5, 0x12d3a92f, 0x0347f362, 0x07481ad7, 0x64aa6b}}}, + /* 13*16^19*G: */ + {{{0x038a2755, 0x18420bcd, 0x1271541b, 0x0434e2ca, 0x07faa537, 0x1abba5a8, 0x12b15705, 0x0c4799ab, 0x4e909a}}, + {{0x03cca3de, 0x1bd24fb1, 0x0a60032b, 0x1aa729a4, 0x159dbb6c, 0x036ea83a, 0x16bb3bc9, 0x10f199c6, 0xae56da}}}, + /* 15*16^19*G: */ + {{{0x183ba64d, 0x012c4acc, 0x116568ea, 0x0c1eef11, 0x040e2bde, 0x10a2f5c7, 0x100efec2, 0x0b845c09, 0xc36745}}, + {{0x0a2181fd, 0x0a6647cb, 0x1de3c518, 0x04d55942, 0x164c7426, 0x0737426c, 0x00cc2038, 0x1a0d396c, 0x3a520a}}} + }, + { + /* 1*16^20*G: */ + {{{0x0037fa2d, 0x0a9e6469, 0x0ff710ca, 0x1d91eaeb, 0x14103043, 0x0420a5df, 0x0350f60d, 0x1c15f83b, 0xe5037d}}, + {{0x1d755bda, 0x072ee420, 0x1207c438, 0x1eb607d8, 0x10bddbd5, 0x0684fdcc, 0x0ed7e7e6, 0x0975529a, 0x457153}}}, + /* 3*16^20*G: */ + {{{0x177e7775, 0x04545370, 0x1b657d8e, 0x02ab2711, 0x091aeb5e, 0x01dd67a9, 0x0f3b9615, 0x075ff2c6, 0x9d896a}}, + {{0x1a056691, 0x1e7b69d5, 0x06494efb, 0x139afdc5, 0x0927de89, 0x1276b928, 0x1c2e53a5, 0x1c87e937, 0xdd91a9}}}, + /* 5*16^20*G: */ + {{{0x1c2a3293, 0x1ef026f1, 0x00d1db17, 0x1170ddd2, 0x0f4cd568, 0x052b9941, 0x1e4b43ac, 0x1dce22c6, 0x8327b8}}, + {{0x0e0df9bd, 0x1e42a70c, 0x0c9a905a, 0x1fb569dc, 0x1708496a, 0x1f53313c, 0x063862ec, 0x04cddc15, 0x4997e}}}, + /* 7*16^20*G: */ + {{{0x0562c042, 0x010d9362, 0x037ec689, 0x1a464697, 0x08ed6092, 0x130ec7cd, 0x05a25f59, 0x15454db6, 0x5ae42a}}, + {{0x0f79269c, 0x082e66fc, 0x1f3636fe, 0x01b72a20, 0x09d4a94e, 0x0eee301c, 0x147aad70, 0x0f80bfe0, 0x99d93a}}}, + /* 9*16^20*G: */ + {{{0x1e85af61, 0x1a440942, 0x12b9d9ac, 0x1dae45ba, 0x01b0f4e8, 0x1b47fb61, 0x03ad66ba, 0x1c84d439, 0x92c23a}}, + {{0x036a2b09, 0x1391b34e, 0x0a1bfb53, 0x075b056c, 0x0d5792d2, 0x0beae39c, 0x0ed027c8, 0x11e02aa3, 0x414cf8}}}, + /* 11*16^20*G: */ + {{{0x07b5eba8, 0x11578d96, 0x063a8db3, 0x17db8ff2, 0x0df422da, 0x1a0bb57c, 0x1c422343, 0x118ed5fb, 0xfee560}}, + {{0x0d0b9b5c, 0x1a8ae9b4, 0x04151e4f, 0x01fe857f, 0x1c14ee38, 0x017cc943, 0x02bec450, 0x12269fcb, 0x380759}}}, + /* 13*16^20*G: */ + {{{0x1c63caf4, 0x0f1dd259, 0x1d4f54a0, 0x1fe75651, 0x06afca28, 0x09da6315, 0x1f988284, 0x1d725ccc, 0x42e544}}, + {{0x169c29c8, 0x03d7604c, 0x1bf17c46, 0x0a1cf6d7, 0x15e7873a, 0x11060ba0, 0x19c7dc7c, 0x1c1f2398, 0x9ff854}}}, + /* 15*16^20*G: */ + {{{0x1e0f09a1, 0x0515ecc2, 0x100ca0e0, 0x0213e372, 0x00efef0a, 0x17695238, 0x138e0e65, 0x16ccaa65, 0x7aed83}}, + {{0x05857d73, 0x02ec66f4, 0x0fd29501, 0x165e601e, 0x12d8ed88, 0x1e855881, 0x1df1f76b, 0x0bf3463d, 0xf5b854}}} + }, + { + /* 1*16^21*G: */ + {{{0x04fce725, 0x0c335057, 0x09b16dc9, 0x11b7a38d, 0x171b4e7e, 0x082f478b, 0x1eb7d7aa, 0x161e9440, 0xe06372}}, + {{0x0eee31dd, 0x1381a7ca, 0x04121c2c, 0x1094ef0e, 0x0488cd74, 0x1dd956ad, 0x13f84a89, 0x0e979c31, 0x7a9089}}}, + /* 3*16^21*G: */ + {{{0x1a328d6a, 0x1d540c46, 0x0b7062f6, 0x1aee752b, 0x08fa7b24, 0x04c8c2d8, 0x18028d1a, 0x0b74c469, 0xc663c0}}, + {{0x1ec9b8c0, 0x1d85db55, 0x0afe7308, 0x0aa3d4a2, 0x11317dd8, 0x1ee793ab, 0x10e34e6b, 0x11abee43, 0x3331e9}}}, + /* 5*16^21*G: */ + {{{0x1996de2f, 0x048e4241, 0x0c94452f, 0x1dbe5dc1, 0x1e4e977c, 0x186f7507, 0x091673ac, 0x105bf70d, 0xd3fc26}}, + {{0x14526f8c, 0x0249120e, 0x1eafc5a3, 0x136931be, 0x181da4e5, 0x03aa6a7b, 0x0863da2d, 0x13348be1, 0xc4f0df}}}, + /* 7*16^21*G: */ + {{{0x03e697ea, 0x03624688, 0x17e0fa17, 0x0cf1f730, 0x1abd19ce, 0x0ff64d1f, 0x008df728, 0x087fd658, 0xc17a4b}}, + {{0x1edc6c87, 0x171dc3ee, 0x07c0aac3, 0x03436aff, 0x01fae96e, 0x1c7b8cb0, 0x05532b85, 0x05aab56b, 0x39355c}}}, + /* 9*16^21*G: */ + {{{0x1163da1b, 0x16961811, 0x04e8c460, 0x1dbdcc1f, 0x11fde9a0, 0x1a4ebfe0, 0x02d1a324, 0x0f944cf2, 0x8f618b}}, + {{0x03bdd76e, 0x1f989088, 0x126db9f1, 0x018cd464, 0x05a42645, 0x0d3a6bd6, 0x0dbad7ef, 0x04be117d, 0x78233f}}}, + /* 11*16^21*G: */ + {{{0x0ec8ae90, 0x142c87f0, 0x0ef177bb, 0x04d725d1, 0x1f1b8cfb, 0x0dc6d641, 0x19bae1b5, 0x1e2b6f43, 0x9798c0}}, + {{0x052844d3, 0x14d61757, 0x0c62389e, 0x092cb7a0, 0x073bee2e, 0x04a4a7ce, 0x1b4f74bb, 0x154eb485, 0xba40e2}}}, + /* 13*16^21*G: */ + {{{0x11d66b7f, 0x0d0cbc78, 0x01f72041, 0x0d24a0a3, 0x084757aa, 0x0dc85c49, 0x159d1f3c, 0x1c7f6b45, 0xfdfa6e}}, + {{0x18e5178b, 0x1547c033, 0x15e37a76, 0x0df3ba27, 0x018c4d84, 0x00e4d1ed, 0x036e4f03, 0x03c44933, 0x4d9cf3}}}, + /* 15*16^21*G: */ + {{{0x1265bcf0, 0x003abc24, 0x071f4c2e, 0x1c56f082, 0x1220e69c, 0x14d230e7, 0x190eb77a, 0x071bc453, 0xfd58ce}}, + {{0x0b996292, 0x19f3d4e7, 0x1c73477c, 0x0c37fc51, 0x1e4fb872, 0x155cd242, 0x056f54e0, 0x1ca6ec64, 0xffe0a5}}} + }, + { + /* 1*16^22*G: */ + {{{0x10559754, 0x056b4846, 0x08fd6150, 0x0217bbc5, 0x0e02204b, 0x1dfcee06, 0x114d6342, 0x0e2b9aba, 0x213c7a}}, + {{0x14b458f2, 0x1f9613a9, 0x1a9fbb77, 0x10a1ebe6, 0x1a190bb4, 0x1683122d, 0x0941c04e, 0x016b5c8c, 0x4b6dad}}}, + /* 3*16^22*G: */ + {{{0x1e05dccc, 0x196c008c, 0x066a4f94, 0x1f47da98, 0x1d172ae3, 0x104b5ca9, 0x00c2551b, 0x1c2ea7b4, 0xb8cef6}}, + {{0x0c6d5750, 0x00a5067e, 0x1ada04cc, 0x0aff86d4, 0x0bd99df7, 0x053a7269, 0x0efda935, 0x0c14d993, 0x302b8a}}}, + /* 5*16^22*G: */ + {{{0x173bb31a, 0x0deff709, 0x16e5ed21, 0x1ef6d6bf, 0x15f49701, 0x05ef175d, 0x0e1780a8, 0x1cef368e, 0x3fb33}}, + {{0x1d215c9e, 0x1a65f34b, 0x1d903538, 0x14f8ed88, 0x1572bc65, 0x0b0d55dd, 0x18a07830, 0x0a4a91df, 0xf36ad9}}}, + /* 7*16^22*G: */ + {{{0x1d9a4ab4, 0x0da8af5e, 0x16edf029, 0x186d830a, 0x17a36717, 0x17bda687, 0x184587c5, 0x1a213d87, 0x4b177c}}, + {{0x035ab6f7, 0x156eff23, 0x1d07d562, 0x0fc4abe2, 0x06b486e3, 0x1b3949b1, 0x0997f6a3, 0x1d34bc5f, 0x3ec966}}}, + /* 9*16^22*G: */ + {{{0x101c23a4, 0x1a37d94d, 0x09273d5b, 0x1482b08f, 0x1cd75c22, 0x1c14dcdc, 0x081b0a80, 0x0a40d44f, 0x5e8703}}, + {{0x10d986f9, 0x10bccb58, 0x1333f684, 0x0e3b0e94, 0x06e2da21, 0x0ae8d716, 0x08879c5d, 0x09df7392, 0x5b9664}}}, + /* 11*16^22*G: */ + {{{0x007b0c66, 0x19f9ae90, 0x1b21bec7, 0x0ffdc8ca, 0x0eb7434a, 0x1227b056, 0x002911c8, 0x003261ad, 0xe545c3}}, + {{0x11f2d470, 0x03fabe93, 0x1688e776, 0x0b051c36, 0x1bcbf97e, 0x17ed1cac, 0x1579f971, 0x01d18c52, 0xe06a34}}}, + /* 13*16^22*G: */ + {{{0x03648bba, 0x12c0c85c, 0x10f1d112, 0x01e160d3, 0x1b39882a, 0x17112f80, 0x160284cf, 0x02af4a9e, 0xb2a442}}, + {{0x00fb6452, 0x037d5a50, 0x0705eec9, 0x10aa2a39, 0x17e31c0d, 0x1e4bc7de, 0x19867a7e, 0x1856d26c, 0xfe4f5f}}}, + /* 15*16^22*G: */ + {{{0x0bab27d0, 0x1b6e9177, 0x11440ff3, 0x1683f458, 0x17007f70, 0x180c8c6c, 0x01946ea5, 0x01e7a8a7, 0x1b908e}}, + {{0x00d3d110, 0x0f433af2, 0x1f946d5c, 0x179526b0, 0x04b9ab5b, 0x1e48c0be, 0x0d79bcd5, 0x0bdd88cd, 0x9b6d62}}} + }, + { + /* 1*16^23*G: */ + {{{0x08fbd53c, 0x0661d1d8, 0x118b377c, 0x0718e15b, 0x19a87e28, 0x09a952a0, 0x0d3a36ee, 0x054f5e96, 0x4e7c27}}, + {{0x17dcaae6, 0x059ca0c0, 0x1df74cf8, 0x172c297f, 0x1681b530, 0x084fb6f7, 0x0c6385bf, 0x0ecd93a1, 0x17749c}}}, + /* 3*16^23*G: */ + {{{0x0521b3ff, 0x114c2327, 0x0a9d433b, 0x180e2fd3, 0x024a5233, 0x0695f4d7, 0x1571d791, 0x06021928, 0x2484e}}, + {{0x0269da7e, 0x00d725c8, 0x0eb22ef3, 0x000dbd24, 0x10eebad7, 0x159e1596, 0x0c341fb0, 0x1415447c, 0x9619d0}}}, + /* 5*16^23*G: */ + {{{0x004ba7b9, 0x0b5bcfd4, 0x1d05d47e, 0x0d48e060, 0x0954e20d, 0x1b86b396, 0x195fbde6, 0x04d9f6d9, 0x16c1c5}}, + {{0x1c5bd741, 0x1adf1d28, 0x126a7311, 0x0ab8037b, 0x094deec7, 0x13a2ce45, 0x10e41898, 0x0f868062, 0xdb157f}}}, + /* 7*16^23*G: */ + {{{0x036683fa, 0x01b243d5, 0x1b02097a, 0x0436a701, 0x07b66958, 0x0e73ba29, 0x06be1ea2, 0x1aea7f26, 0x3973c}}, + {{0x1f4a577f, 0x1afd95bb, 0x1a6077b7, 0x1109c31f, 0x1a26cd77, 0x095b195a, 0x0e8d90f8, 0x05986194, 0x38cf5a}}}, + /* 9*16^23*G: */ + {{{0x00bf6f06, 0x0059ccce, 0x010ed5c6, 0x1826644a, 0x05765713, 0x027a5810, 0x054470b0, 0x174e5d9e, 0xba6a9b}}, + {{0x181db551, 0x195f7b83, 0x1a5eabf8, 0x1a29ef58, 0x0bd8e9e5, 0x05f972ac, 0x06c0c808, 0x07166942, 0x13771e}}}, + /* 11*16^23*G: */ + {{{0x11231a43, 0x08f7cf83, 0x0b50ee7f, 0x0a29accb, 0x0442f44d, 0x0ca8326f, 0x174b62bb, 0x1984f989, 0x35c5bc}}, + {{0x1620c8f6, 0x0db97228, 0x0f3c2b9f, 0x0f49980c, 0x0589d4cf, 0x0c105b7d, 0x1b39cd39, 0x0e4772e8, 0xe3675}}}, + /* 13*16^23*G: */ + {{{0x1dd40609, 0x1a05e2b7, 0x00735daf, 0x0321301b, 0x0356ac74, 0x1897e2c4, 0x1af2848b, 0x048b8ab0, 0xfd479c}}, + {{0x0a64ca53, 0x0f1789b3, 0x07291ce7, 0x075dae4c, 0x041fd911, 0x0bd21e4c, 0x1fbfcb2b, 0x16a4d295, 0x3069cf}}}, + /* 15*16^23*G: */ + {{{0x0b799a7f, 0x0db817a9, 0x0e3a1093, 0x116d9aa7, 0x07d544f1, 0x075cd796, 0x0192f7b6, 0x0547599b, 0x6c4000}}, + {{0x13c81e32, 0x1ae64166, 0x0120fda2, 0x157a9904, 0x1dcbdc07, 0x01b5070e, 0x16f9a42e, 0x02a616c6, 0x95c2dc}}} + }, + { + /* 1*16^24*G: */ + {{{0x00fb27b6, 0x1213f142, 0x10c15d8c, 0x1c7b657c, 0x06aa5c76, 0x1c56b0b4, 0x0c6c43c8, 0x07b7cef1, 0xfea74e}}, + {{0x123cb96f, 0x00e9edbf, 0x0fdedddc, 0x16b2d72e, 0x0af93126, 0x1a6f665b, 0x0ca5f3d9, 0x1b736162, 0x6e0568}}}, + /* 3*16^24*G: */ + {{{0x1e889756, 0x0ec0d74d, 0x0012ec97, 0x16c932f6, 0x099f3f27, 0x0cbd938c, 0x1aa089b3, 0x1866423f, 0x762e8b}}, + {{0x1ca6b774, 0x0f12cf03, 0x013e9789, 0x05b66291, 0x0e347197, 0x0278a4c1, 0x05f0f1f3, 0x04c15e7d, 0xc02894}}}, + /* 5*16^24*G: */ + {{{0x0975d2ea, 0x17baf4b8, 0x053a3a89, 0x0559f420, 0x0f4a91e5, 0x1edd9184, 0x14d23866, 0x08fbec12, 0xdf077d}}, + {{0x11936f95, 0x11e16cf1, 0x0f749dea, 0x1d8b709f, 0x0527c8a1, 0x012e4c51, 0x1d109321, 0x11001def, 0xf8617a}}}, + /* 7*16^24*G: */ + {{{0x1c4c92d7, 0x1c248fdd, 0x10e46d16, 0x169addca, 0x1142935d, 0x0f5419a5, 0x080cb85f, 0x0eb17a7b, 0x9f3e7d}}, + {{0x114906dd, 0x05ddfe7d, 0x0538461b, 0x144607ad, 0x11502452, 0x1590e5d5, 0x19ad6218, 0x03d4efa8, 0xecd284}}}, + /* 9*16^24*G: */ + {{{0x12a8c483, 0x1706b995, 0x0102b0d6, 0x1619118a, 0x15281174, 0x01e9177c, 0x1e7b70e3, 0x0baf6b99, 0xa0cc79}}, + {{0x12cc6ba9, 0x04b3a2ac, 0x1a4d8154, 0x091e37be, 0x1df786b3, 0x07e4b918, 0x1cfb88dd, 0x045f1670, 0xabc301}}}, + /* 11*16^24*G: */ + {{{0x05dd3aee, 0x1878db5e, 0x05b4bc85, 0x0a75151f, 0x176ca131, 0x154d6354, 0x1f338388, 0x14a2aa78, 0x6d1c50}}, + {{0x1df597f7, 0x171aa727, 0x1b54eb7f, 0x1c621551, 0x1d474851, 0x19001143, 0x1f725dc9, 0x11c0d57b, 0xafff14}}}, + /* 13*16^24*G: */ + {{{0x04a6d0bb, 0x1c654dbf, 0x086bf719, 0x1a6245eb, 0x0418f659, 0x136c5453, 0x07cfcc46, 0x0c3172ff, 0x5e5f1d}}, + {{0x1033eaf9, 0x141c23c8, 0x1bd94e85, 0x0abe5ca0, 0x121da725, 0x15e68273, 0x1bdcd63d, 0x0560d4fc, 0xd7b150}}}, + /* 15*16^24*G: */ + {{{0x0f005e3f, 0x0d4daf22, 0x10e6f4b7, 0x0d1c637d, 0x1a1495af, 0x05cd6700, 0x09ffff4f, 0x0d6782c8, 0xf8138a}}, + {{0x0f357eb7, 0x16bf0101, 0x12f884d0, 0x18837aaa, 0x1cb51f4e, 0x0af2bd52, 0x0f67e740, 0x077df69d, 0xca758f}}} + }, + { + /* 1*16^25*G: */ + {{{0x17bdde39, 0x16015220, 0x1810ca54, 0x09c2f36e, 0x168d3154, 0x0b86accc, 0x1c384289, 0x027ecef9, 0x76e641}}, + {{0x1901ac01, 0x058ba968, 0x1b480cad, 0x1467a56a, 0x1f0d35e2, 0x136b8340, 0x173d5dc1, 0x11bdc9d2, 0xc90ddf}}}, + /* 3*16^25*G: */ + {{{0x0078ee8d, 0x182848e6, 0x1a46510b, 0x1e419ca0, 0x14ff64eb, 0x1931d54d, 0x06f897fd, 0x15b0b3b5, 0xd08e57}}, + {{0x0da63e86, 0x0cbfa6e1, 0x08bb677a, 0x1def9f28, 0x06df4123, 0x19773abf, 0x035cb585, 0x13095691, 0x852e97}}}, + /* 5*16^25*G: */ + {{{0x029129ec, 0x0c8a3382, 0x12095205, 0x1c759e3c, 0x11d080ca, 0x1f407669, 0x149d7d62, 0x10bc9a89, 0x7da6c0}}, + {{0x0cd9ff0e, 0x1a857715, 0x12961aba, 0x11810ca9, 0x027bf044, 0x0103a48b, 0x015d4474, 0x0d773e83, 0xf49814}}}, + /* 7*16^25*G: */ + {{{0x11654f22, 0x1c1ea4aa, 0x06abba53, 0x0fe72846, 0x1d94fb2f, 0x0800df34, 0x19b886fa, 0x19feb837, 0x90d090}}, + {{0x001a43e1, 0x1aef02bb, 0x08fe1d03, 0x0c6aca7b, 0x170336dd, 0x010f035f, 0x186a54fc, 0x03a5759e, 0xcd569a}}}, + /* 9*16^25*G: */ + {{{0x076b19fa, 0x1b77b28e, 0x020675c6, 0x0dc0da0d, 0x1292ed9d, 0x16188410, 0x07b31cc8, 0x0b0f9e3a, 0xda4798}}, + {{0x126f5af7, 0x15137759, 0x14ff081a, 0x17a27d2a, 0x0569ea67, 0x1483bf0b, 0x1c0745cd, 0x0f137995, 0xebb1d7}}}, + /* 11*16^25*G: */ + {{{0x19135dbd, 0x0c97db2d, 0x1618c7b3, 0x010f5e73, 0x1897cf0c, 0x157ac174, 0x19ab605e, 0x00951bbd, 0xe3e475}}, + {{0x0748045d, 0x083579f2, 0x12576a5a, 0x0405febd, 0x03ffea5a, 0x040ca95c, 0x1b102e63, 0x1f013978, 0x930a5b}}}, + /* 13*16^25*G: */ + {{{0x0dee455f, 0x1f85cf2e, 0x13901d72, 0x0fffcdd1, 0x1db4aff6, 0x099c7c05, 0x06c291d1, 0x0dfd0e15, 0x7e8c65}}, + {{0x171b9cba, 0x19ef4cc0, 0x1d1989c5, 0x05a2ce8d, 0x1a53b4aa, 0x1b07a401, 0x103ca8fd, 0x0659460e, 0xbdddc6}}}, + /* 15*16^25*G: */ + {{{0x0698b59e, 0x1bcb5cdb, 0x0d11e90d, 0x06b24b12, 0x1c7260a3, 0x01ad59f1, 0x1ac56fac, 0x1f12352b, 0x3df841}}, + {{0x0b92baf5, 0x07c733cb, 0x12527e2f, 0x190cf642, 0x0f3867bf, 0x1d74788e, 0x0307680a, 0x1bf31612, 0xb38fe6}}} + }, + { + /* 1*16^26*G: */ + {{{0x0bcbb891, 0x158a8121, 0x09b2fb8e, 0x198c87be, 0x18f9a8f7, 0x0dd53a1f, 0x0f87a0a0, 0x0d607655, 0xc738c5}}, + {{0x099a84c3, 0x1f39aecb, 0x0033fa45, 0x029ddef1, 0x1bbbb823, 0x0797565f, 0x094dfdc6, 0x0f12a35a, 0x893fb5}}}, + /* 3*16^26*G: */ + {{{0x0761d58d, 0x05d5799c, 0x15838bcd, 0x1937c811, 0x0df7aca4, 0x0051ab90, 0x05184289, 0x04f047ec, 0xb8c461}}, + {{0x1d1051a4, 0x1c7505d4, 0x041f16d8, 0x0a08f0bc, 0x1c5053f7, 0x0c7b4bf9, 0x0df45291, 0x0d8a2e1c, 0x8f9ed9}}}, + /* 5*16^26*G: */ + {{{0x050b0040, 0x0d859820, 0x04d2b70b, 0x08fb73e0, 0x03671f3f, 0x04c9ff4d, 0x07de8d43, 0x13ee204e, 0x8d56e}}, + {{0x1b3fd0a1, 0x0c7133d2, 0x05e0afad, 0x0f88e41c, 0x1b285f6d, 0x0a8546bc, 0x0a887ff4, 0x15d7a153, 0xa12185}}}, + /* 7*16^26*G: */ + {{{0x13573b7f, 0x0b2b1ef8, 0x02d89c3d, 0x1438bda6, 0x05a37889, 0x07cbbdf3, 0x198d0788, 0x065a85f9, 0xdc13f2}}, + {{0x0c1f2ba6, 0x15669142, 0x1012c710, 0x0aa8e02e, 0x10a76704, 0x086d4254, 0x1030f1d0, 0x100853c6, 0xc909ba}}}, + /* 9*16^26*G: */ + {{{0x07ae9ceb, 0x017ac85c, 0x1bcb452c, 0x1843d4e1, 0x119a8226, 0x0ab2ed90, 0x1c1cebc6, 0x1cc03bef, 0x25c02d}}, + {{0x0bc6e275, 0x1848689a, 0x1961c991, 0x0c83be14, 0x111d537c, 0x0706e7d6, 0x00f03221, 0x1a590247, 0x8a9fea}}}, + /* 11*16^26*G: */ + {{{0x0c5a3c34, 0x1c04c7b7, 0x16527f87, 0x1d058052, 0x03e58aec, 0x0fa653d7, 0x1273a2ae, 0x03659f1c, 0xfedd9d}}, + {{0x013d7714, 0x15aa5fa7, 0x0fe0a5d8, 0x1d6a8d33, 0x14b00ada, 0x02989647, 0x0382c2fa, 0x18630a77, 0xa52e24}}}, + /* 13*16^26*G: */ + {{{0x0ab6a396, 0x1a72a68d, 0x04d81da6, 0x04372342, 0x088b3730, 0x16bfaf42, 0x1230b7b8, 0x10d78dd4, 0x3e0e32}}, + {{0x1980e27e, 0x1598f246, 0x11a3da8b, 0x002083e6, 0x13fc66ab, 0x1f0ef5a2, 0x1e593cc7, 0x0e5f4766, 0xca4481}}}, + /* 15*16^26*G: */ + {{{0x141023ec, 0x179ac311, 0x1b3d5c2a, 0x0bb1eedf, 0x0b9af564, 0x101004c1, 0x14a1260b, 0x06101865, 0x344ab9}}, + {{0x1e1eeb87, 0x07c4c148, 0x0e6575c1, 0x1d2ed5f8, 0x14c5ffc4, 0x1968f528, 0x18a9cfe3, 0x00856488, 0x6e1c2b}}} + }, + { + /* 1*16^27*G: */ + {{{0x08f6c14b, 0x1974fb2c, 0x0494050d, 0x0e5cbe75, 0x12877d1d, 0x03b1be4b, 0x0e078993, 0x0ca916cb, 0xd89562}}, + {{0x1d7d991f, 0x09b1f6ba, 0x0c19f85e, 0x051ac657, 0x140eb034, 0x03040c61, 0x1ab9ca3b, 0x071e578f, 0xfebfaa}}}, + /* 3*16^27*G: */ + {{{0x0127b756, 0x05d43ffb, 0x0825c120, 0x0517c957, 0x0b416034, 0x116d2830, 0x0499cb4d, 0x05ee2dbe, 0x6d8c78}}, + {{0x1f172571, 0x0a8fba55, 0x1f373299, 0x154db45a, 0x14daf4e3, 0x14169b69, 0x04445166, 0x0112dfb7, 0x99aedf}}}, + /* 5*16^27*G: */ + {{{0x158cf17a, 0x0f70d39b, 0x0208d493, 0x10bb974b, 0x097f8f1f, 0x0d778da0, 0x0b2a3416, 0x1bb2b7ef, 0xebcabe}}, + {{0x1caa0ccd, 0x0366e2fa, 0x0b3a5711, 0x15a425a1, 0x12e6b10f, 0x050db3e1, 0x072c0b00, 0x01f1e457, 0x47d3ce}}}, + /* 7*16^27*G: */ + {{{0x0c855c5b, 0x077728ad, 0x1f22beef, 0x0ac43402, 0x1fc28118, 0x0d1b4f0b, 0x189114cc, 0x05c97a99, 0xe8df4d}}, + {{0x0e465650, 0x0eaf3961, 0x07935f56, 0x076abe3c, 0x132c5966, 0x0da7acf7, 0x0c991113, 0x0e188ff3, 0x6c57fd}}}, + /* 9*16^27*G: */ + {{{0x12e7e454, 0x047aded2, 0x03985434, 0x05dfde1e, 0x01662fe3, 0x03011d4c, 0x00ca4492, 0x1ae31d95, 0x4068d3}}, + {{0x18ef191e, 0x1cd66f2e, 0x10dccc9d, 0x1a43da27, 0x138d1988, 0x0a2cbece, 0x1eaae7b0, 0x16e4a948, 0x8cd853}}}, + /* 11*16^27*G: */ + {{{0x06c5d939, 0x02bd6fc2, 0x0a4cf782, 0x0b450ef7, 0x0027ea47, 0x19973065, 0x1782d56f, 0x19b63b04, 0x12550e}}, + {{0x19e757c9, 0x153a7e2a, 0x16350c64, 0x16e83fd9, 0x04a72838, 0x121e0bb9, 0x1e9d5123, 0x069f0e5a, 0x7b8f83}}}, + /* 13*16^27*G: */ + {{{0x16c8a56f, 0x06855632, 0x1cdd084e, 0x1278a869, 0x0d08f850, 0x1bda9d7d, 0x17531a6e, 0x035876b0, 0x944d67}}, + {{0x1a7be289, 0x0fa6e32e, 0x01945fae, 0x0982e9ba, 0x0c61967d, 0x1c9b099d, 0x1ffd3050, 0x12ef6a03, 0xa71065}}}, + /* 15*16^27*G: */ + {{{0x0e08f15a, 0x175c50c5, 0x04a402eb, 0x13cadb90, 0x1c305fd6, 0x01b2ad69, 0x0833f9ac, 0x1239a133, 0x86a54e}}, + {{0x01388308, 0x09268f3e, 0x0d49534d, 0x053a24b6, 0x16867771, 0x146836ba, 0x1180e9ca, 0x0906f4f0, 0xcfee61}}} + }, + { + /* 1*16^28*G: */ + {{{0x0f676e03, 0x08a852b2, 0x1a13b752, 0x1f8e6d27, 0x08761cef, 0x1219ab8f, 0x1463ac3d, 0x006552ae, 0xb8da94}}, + {{0x0efdf6e7, 0x0447273a, 0x1fced445, 0x18b09b2b, 0x008b092c, 0x0e64bb14, 0x07935f26, 0x148900b4, 0x2804df}}}, + /* 3*16^28*G: */ + {{{0x06e1346b, 0x10cc24ee, 0x16bc717a, 0x1cf62070, 0x152c05ab, 0x1b0f8a68, 0x042f9531, 0x1fe1305a, 0x69068}}, + {{0x17226c13, 0x1dac52a6, 0x11809b9e, 0x0d127329, 0x0442aa4f, 0x0d95e843, 0x189b6a17, 0x1c1217fb, 0xb863e3}}}, + /* 5*16^28*G: */ + {{{0x1ca1f6a1, 0x07348fe6, 0x033fc68c, 0x197a2869, 0x06ce1068, 0x0e2e58f4, 0x1d854a1b, 0x127964b2, 0x898c34}}, + {{0x164f647c, 0x056e1078, 0x0af5e729, 0x0f9f2f3e, 0x06e93b2a, 0x0a122956, 0x15527611, 0x10d56ad4, 0x75f759}}}, + /* 7*16^28*G: */ + {{{0x1d1e3998, 0x134f01e1, 0x0810ca2a, 0x0d91722f, 0x0274e5e5, 0x0ceb8115, 0x0fc0694a, 0x1fda5231, 0xb213e2}}, + {{0x125fb81e, 0x0165ee31, 0x17b45d7b, 0x082cb7d7, 0x03bc3d53, 0x0f5fc1d2, 0x104b0f58, 0x1841e5a7, 0x229f8e}}}, + /* 9*16^28*G: */ + {{{0x025be234, 0x05f0ff65, 0x17cd41c0, 0x07c7ce1b, 0x06e060e8, 0x05d348b0, 0x04f97474, 0x1b02d8ff, 0x4b3b3a}}, + {{0x120e8362, 0x11dbf01c, 0x0846e101, 0x0ffb259e, 0x0c04c41e, 0x14b6fec6, 0x1271e1d7, 0x0770bb57, 0x5eec02}}}, + /* 11*16^28*G: */ + {{{0x0289f55e, 0x0b31a53f, 0x11d9c1ee, 0x0d61e1c5, 0x165be297, 0x08d813c4, 0x1e580809, 0x16dbb609, 0x9f7b88}}, + {{0x1e1e4bde, 0x1e69db2f, 0x0428ac6c, 0x0a6dc1d6, 0x1c71fc0e, 0x035a14c7, 0x03def8c5, 0x1098e082, 0x32f9f7}}}, + /* 13*16^28*G: */ + {{{0x1dfe1d2b, 0x12a4e460, 0x1a1e3945, 0x07ea13ca, 0x173a4c49, 0x056fe9fd, 0x038f9db3, 0x1d396e89, 0xd58a43}}, + {{0x0cd50922, 0x0793cadc, 0x0f5befff, 0x137442b9, 0x0276b54d, 0x14899414, 0x0f3c429c, 0x0d740b10, 0xfc1786}}}, + /* 15*16^28*G: */ + {{{0x049c795e, 0x120a8df1, 0x13a01784, 0x080d5533, 0x1ea4eed4, 0x0b4e1e13, 0x0c4335b6, 0x072e2230, 0x21d271}}, + {{0x19208ece, 0x0009761c, 0x17edd86c, 0x03289495, 0x1b4c3d67, 0x0dc2a915, 0x13a85dcd, 0x16960eb5, 0x94c5f9}}} + }, + { + /* 1*16^29*G: */ + {{{0x03c0df5d, 0x0d08bbc7, 0x15a9e4bc, 0x13dff6a2, 0x17fab201, 0x0d5ca3ae, 0x0ce9f62b, 0x028883f6, 0xe80fea}}, + {{0x0ac9ec78, 0x05a148db, 0x0c8baa7f, 0x0abd015e, 0x094472d1, 0x1b4651e5, 0x01dc7a25, 0x0fec71c0, 0xeed1de}}}, + /* 3*16^29*G: */ + {{{0x17592d55, 0x001acf66, 0x18d4064b, 0x0b728e81, 0x0e3b106d, 0x17b4b19e, 0x149822bf, 0x1b789420, 0x5d2ec6}}, + {{0x0f5183a7, 0x1372e875, 0x04545d09, 0x14f79b5a, 0x0d6950e2, 0x087d1346, 0x17ad63dc, 0x1f138dc8, 0xa92cd}}}, + /* 5*16^29*G: */ + {{{0x1e8f9f5c, 0x08fa5a4f, 0x02029466, 0x03e3c2b3, 0x1404d736, 0x171a10af, 0x1d0bf8b2, 0x1876237e, 0xac371d}}, + {{0x125a503c, 0x1d41ff99, 0x1d478745, 0x0a68b1dc, 0x0e735229, 0x00f3992a, 0x11dffc84, 0x1830e134, 0xc51616}}}, + /* 7*16^29*G: */ + {{{0x19e33446, 0x050e46a8, 0x0bce177d, 0x127788a5, 0x0a17a408, 0x005e8111, 0x10324d23, 0x07429e30, 0x894200}}, + {{0x06387689, 0x069c5007, 0x19d3e610, 0x1aee6cf3, 0x1e4e06bf, 0x16b6877e, 0x1de9362c, 0x12b2b4a0, 0xa9fd03}}}, + /* 9*16^29*G: */ + {{{0x1913cb26, 0x0b9464ad, 0x0ef5b40f, 0x16833802, 0x05c9899e, 0x1227faa8, 0x0aa28b36, 0x0d661468, 0x277026}}, + {{0x1348a7a2, 0x1f38b99f, 0x0056faef, 0x01923799, 0x0b324e94, 0x092683f9, 0x0c69554b, 0x0bcf361b, 0xf649bc}}}, + /* 11*16^29*G: */ + {{{0x195e8247, 0x0555010a, 0x01b346bc, 0x1fb88aad, 0x0ba9097b, 0x13700e7c, 0x1485e397, 0x1a70797d, 0x75e4d0}}, + {{0x19982d22, 0x111fecea, 0x06b624f2, 0x156b6dd5, 0x126d47dd, 0x0b8763db, 0x0641d07e, 0x142ea821, 0x1fce42}}}, + /* 13*16^29*G: */ + {{{0x06333323, 0x03cfa26d, 0x1d2afd1d, 0x177838d1, 0x0da849cb, 0x06b02cc2, 0x0fc0fc08, 0x07066c37, 0x3ed1b6}}, + {{0x15d61ba3, 0x189fe245, 0x1e3dca52, 0x0e514216, 0x1929ea9b, 0x04c4b447, 0x1b9d765f, 0x14916b69, 0xd84f2d}}}, + /* 15*16^29*G: */ + {{{0x133980bf, 0x1282bea5, 0x17402ebc, 0x06e05ca1, 0x0dd4368a, 0x1ebb91a4, 0x0606e11b, 0x1e0d4eb0, 0x70fdd2}}, + {{0x00b75785, 0x17754675, 0x15d29584, 0x006b070b, 0x0596b0a1, 0x008688f7, 0x1a5a55e9, 0x181a1ab0, 0x5edfca}}} + }, + { + /* 1*16^30*G: */ + {{{0x04e16070, 0x0e03dde6, 0x1f5a4577, 0x0304063d, 0x07543f2a, 0x04728eab, 0x010c4ee9, 0x0f7bf9ae, 0xa30169}}, + {{0x1e177ea1, 0x0068d020, 0x084684c3, 0x0bb7ef81, 0x00f9b173, 0x04fd12ea, 0x13d42060, 0x039f6cfc, 0x7370f9}}}, + /* 3*16^30*G: */ + {{{0x138011fc, 0x18093800, 0x1ca15899, 0x12d4cf5a, 0x00a4d835, 0x09984110, 0x0c4455ac, 0x146102bd, 0x6e8313}}, + {{0x1f15ab7d, 0x165b4fd1, 0x1147e69a, 0x1f22b5d3, 0x0c30426a, 0x16d900ed, 0x08130684, 0x117b849e, 0xc14781}}}, + /* 5*16^30*G: */ + {{{0x100e6ba7, 0x1d3a4dc6, 0x045bdfd4, 0x0dd8b689, 0x1e1b43d3, 0x101c526c, 0x147caf47, 0x0132f090, 0xf952a9}}, + {{0x0175e4c1, 0x0dd77728, 0x18a8ae63, 0x0e2cf698, 0x1a0f6555, 0x1b51713f, 0x1afe184d, 0x0b611579, 0xd8a93a}}}, + /* 7*16^30*G: */ + {{{0x03aa0e93, 0x08032d14, 0x1ec7d89a, 0x1c72875d, 0x0893a8f2, 0x18d0cecf, 0x1b9d4100, 0x0bc63a7f, 0x94016d}}, + {{0x07addac2, 0x07769344, 0x15ec1e8e, 0x086e7754, 0x06fd7f48, 0x0e9aa777, 0x165900d5, 0x1dcb88a9, 0x675032}}}, + /* 9*16^30*G: */ + {{{0x0266b17b, 0x07a43170, 0x18aeccac, 0x0ad14404, 0x109c2023, 0x1c42354f, 0x0a246ee5, 0x0e9ab3f6, 0xef22d1}}, + {{0x19dac83e, 0x1537021b, 0x10d06dcc, 0x0e4edee3, 0x0a1073ee, 0x0661d71a, 0x11d5a3e7, 0x192f5649, 0xbc5784}}}, + /* 11*16^30*G: */ + {{{0x12d382a0, 0x18980ad4, 0x1b366b88, 0x1b9779c5, 0x1f927f28, 0x063c0596, 0x04b4e72b, 0x19c99d71, 0xb5f7ef}}, + {{0x05b4b532, 0x117855dd, 0x0b3e316e, 0x1612da53, 0x1ddd371f, 0x0be37065, 0x08d4f025, 0x0b6a387e, 0x684354}}}, + /* 13*16^30*G: */ + {{{0x012cffa5, 0x13492322, 0x0331711f, 0x1a8410cd, 0x0624389e, 0x0a6c7dea, 0x01d9021d, 0x1a565ce2, 0x1cddc3}}, + {{0x1521954e, 0x0f36c4e6, 0x0dad4a2b, 0x193084d6, 0x0b08ac41, 0x0935fca1, 0x0298ff6c, 0x01965e3f, 0x1e476a}}}, + /* 15*16^30*G: */ + {{{0x14a9f22f, 0x1aff21c9, 0x1ea38ab4, 0x10338a42, 0x035b0cc0, 0x05c5ca44, 0x04e7c87e, 0x0b3e4b9d, 0x2accb3}}, + {{0x175c4927, 0x1baee59d, 0x0e9542de, 0x17af7d8b, 0x0edf1154, 0x1d1bf6f8, 0x0b946484, 0x1d2b115a, 0xd518a4}}} + }, + { + /* 1*16^31*G: */ + {{{0x1fb04ed4, 0x1bd631f1, 0x0c1fffea, 0x18661622, 0x18de208c, 0x0e828933, 0x04d918fe, 0x16713ad7, 0x90ad85}}, + {{0x0b6ef150, 0x08ea6a46, 0x00a25366, 0x1df57c2b, 0x022b839a, 0x05eca139, 0x0986bff7, 0x06c41470, 0xe507a}}}, + /* 3*16^31*G: */ + {{{0x10b7b678, 0x13aed99d, 0x1d8e0598, 0x18862379, 0x16c76f13, 0x15e52135, 0x0c6e8661, 0x0e669c84, 0x186e49}}, + {{0x18d91fc1, 0x1d03b797, 0x054d7729, 0x0ee44a89, 0x1e67e110, 0x0412e05b, 0x1612a9ff, 0x1c9300f7, 0xc0d460}}}, + /* 5*16^31*G: */ + {{{0x13421fb8, 0x18372e5d, 0x16957433, 0x12e3e5de, 0x12412984, 0x159a61db, 0x1d8b9f81, 0x1069edb7, 0x61c8d}}, + {{0x0e3ccd80, 0x0af7b342, 0x1bf374a6, 0x0e269674, 0x1eb5c806, 0x092c8702, 0x12deea4e, 0x1b320076, 0x6dfc6a}}}, + /* 7*16^31*G: */ + {{{0x0f6b35a4, 0x0925f0c5, 0x09fed21c, 0x1e6f4d56, 0x068ad889, 0x1920399d, 0x144edcd8, 0x074411dc, 0xf6a6b6}}, + {{0x01f422a6, 0x175b7f64, 0x1b8618b2, 0x0aeadceb, 0x0186f19d, 0x1b827ab0, 0x0e2c72b4, 0x150005a2, 0x3df7c8}}}, + /* 9*16^31*G: */ + {{{0x06954c11, 0x0b411f45, 0x1834062e, 0x1148782a, 0x178ff7fa, 0x0d878a83, 0x0dd88834, 0x051850d8, 0x87a2fc}}, + {{0x072a8b45, 0x0b719971, 0x1e0492dd, 0x11267e54, 0x07532cc4, 0x0a46d069, 0x13be5ec6, 0x1168b55d, 0x33ad51}}}, + /* 11*16^31*G: */ + {{{0x02706ab6, 0x123a3957, 0x194f036b, 0x16683ba5, 0x04cfe3c0, 0x177e5e1c, 0x069a1155, 0x008dcf10, 0xe1472e}}, + {{0x1d58de05, 0x174350b4, 0x0f349d4d, 0x113aaa8a, 0x021f8aa5, 0x08cbc643, 0x1f1a0fda, 0x1548f8b1, 0x82cd92}}}, + /* 13*16^31*G: */ + {{{0x07a84fb6, 0x1fd72a10, 0x0854087a, 0x06d0ea1f, 0x0b9ebc42, 0x06b00f24, 0x1bd77a2d, 0x19009f15, 0x1caf92}}, + {{0x07149109, 0x158c0c81, 0x0b399d85, 0x1982d2d4, 0x01622ec1, 0x127c7f88, 0x14e92069, 0x0b592edc, 0xbc24b8}}}, + /* 15*16^31*G: */ + {{{0x0a955911, 0x1b467f0a, 0x17b54b6d, 0x1c2d44c1, 0x18397107, 0x17f4d9eb, 0x14349627, 0x0d35e12c, 0x705bfd}}, + {{0x1fd200e4, 0x1dbe349f, 0x10b9cb62, 0x1e76a454, 0x051fa297, 0x1ec0faa0, 0x06429f98, 0x02616e7f, 0xe14aa4}}} + }, + { + /* 1*16^32*G: */ + {{{0x1ec4c0da, 0x1bda2264, 0x0fa8cd46, 0x18acf0e4, 0x1162ee88, 0x00d6cc0f, 0x1cce48e7, 0x1a5ec76b, 0x8f68b9}}, + {{0x101fff82, 0x11e5fbca, 0x1442ff7c, 0x1459fd2a, 0x0215dbbe, 0x08615b5f, 0x061b7876, 0x05b740c7, 0x662a9f}}}, + /* 3*16^32*G: */ + {{{0x123809fa, 0x0715c76e, 0x16552f86, 0x08b966a3, 0x11f08fd8, 0x19b1f922, 0x1c8a2ea4, 0x17c5ca13, 0x38381d}}, + {{0x131fed52, 0x0b83a8c1, 0x163c936f, 0x03f99665, 0x0b1cc368, 0x02d2a907, 0x1f72c250, 0x0141f722, 0xe4a32d}}}, + /* 5*16^32*G: */ + {{{0x17c2a310, 0x15213244, 0x04898c0f, 0x0d5d4a80, 0x099a1f18, 0x0dc15523, 0x0b9bda48, 0x049c86e5, 0x492627}}, + {{0x1e27ded0, 0x020db40a, 0x17fe3383, 0x0c6c254e, 0x0303b6d1, 0x1d2b4b8a, 0x0fe568b3, 0x0e7794f5, 0x1337e7}}}, + /* 7*16^32*G: */ + {{{0x0ebd2d31, 0x1c2583ce, 0x01b6e344, 0x1834adfe, 0x1e2f84dc, 0x09d9f23b, 0x12435789, 0x11834481, 0xe30656}}, + {{0x12546e44, 0x095a041c, 0x0dce099a, 0x1900857c, 0x10db6ffb, 0x15883fbe, 0x0982223c, 0x1c6f1268, 0xeac6f}}}, + /* 9*16^32*G: */ + {{{0x163136b0, 0x09861cf1, 0x0d077671, 0x17f1b355, 0x1d63374e, 0x073b11fd, 0x1bf09c6c, 0x01c48519, 0x3b9e10}}, + {{0x0cdbbc8a, 0x09f60b7b, 0x14c7e065, 0x1c514675, 0x15b26a2a, 0x19f5c7a3, 0x0dc77c54, 0x02a5a2d7, 0xfafb98}}}, + /* 11*16^32*G: */ + {{{0x0f485d3f, 0x10478239, 0x01efbba5, 0x140ed102, 0x0def717c, 0x05407aef, 0x06a4addb, 0x092e2559, 0xbb0aad}}, + {{0x1ca2f975, 0x1c9c9281, 0x19c2fff9, 0x14b5f462, 0x1da34895, 0x100fb94b, 0x11e63b34, 0x0a78b06a, 0xea699c}}}, + /* 13*16^32*G: */ + {{{0x16718dc9, 0x177699d1, 0x0448f792, 0x0b169b60, 0x00113e1e, 0x158cbd7f, 0x130353a3, 0x191c9ddf, 0x79090a}}, + {{0x1cfae7c5, 0x11991588, 0x0a4022e5, 0x0d5f6e17, 0x0aa56dd3, 0x0b65e6cd, 0x0e3c4f60, 0x0572320b, 0xeaab72}}}, + /* 15*16^32*G: */ + {{{0x1f60c7d1, 0x134b4a63, 0x1dd6b4a8, 0x0e3bcf9a, 0x1ba668dd, 0x0dde72a4, 0x0d54700f, 0x15bd3f2f, 0xe77c81}}, + {{0x02d72449, 0x162c0f94, 0x0a61b4d3, 0x08e1ee38, 0x01543631, 0x1d991f54, 0x0c8717f0, 0x0f1ddf02, 0x3acf14}}} + }, + { + /* 1*16^33*G: */ + {{{0x13231e11, 0x1437ea82, 0x1a078f99, 0x11d0ca06, 0x036091f4, 0x0ffc8cc6, 0x17597fe6, 0x002ed5f0, 0xe4f3fb}}, + {{0x0feb73bc, 0x1161c2bb, 0x14747260, 0x0fce9d92, 0x0b7286cc, 0x13687501, 0x1c705986, 0x075a1de9, 0x1e6363}}}, + /* 3*16^33*G: */ + {{{0x0bf05bd6, 0x1ccf8273, 0x0aa65194, 0x0adc0642, 0x10deca2f, 0x1a8ff5a3, 0x1fa420cb, 0x0837dc89, 0x900c32}}, + {{0x100d358b, 0x129569df, 0x13bec577, 0x10a6b078, 0x12439d69, 0x19022b85, 0x03d7e571, 0x1d1d163e, 0x6c31f9}}}, + /* 5*16^33*G: */ + {{{0x1f105c50, 0x13e14664, 0x04e1495e, 0x01bddef6, 0x033cd82e, 0x061a01e1, 0x02ab58a3, 0x0c5560b2, 0x5a8d03}}, + {{0x18a4cde9, 0x04d900c1, 0x1404f0d7, 0x0bed14cd, 0x1ff74a60, 0x15b920a1, 0x14da4da9, 0x16227a9c, 0xc059ea}}}, + /* 7*16^33*G: */ + {{{0x12d64feb, 0x03f0c5cd, 0x048a4b19, 0x05f14b25, 0x1a4e8377, 0x1d2bbb65, 0x182923bc, 0x0062465e, 0xd93f4d}}, + {{0x14698359, 0x187deac9, 0x124368de, 0x008617dd, 0x08c4d93e, 0x188e2a6e, 0x1cce88dc, 0x0ba8b964, 0x792555}}}, + /* 9*16^33*G: */ + {{{0x039fbc84, 0x1110266a, 0x15e8059c, 0x00c522c0, 0x0c65b7e7, 0x115e3315, 0x01106c53, 0x18dc6de5, 0x2f0769}}, + {{0x1c201bec, 0x1dc816f0, 0x137575cf, 0x0f36d498, 0x02149cca, 0x1803cc87, 0x1777e977, 0x0e49ae77, 0xb434f3}}}, + /* 11*16^33*G: */ + {{{0x06a758ea, 0x09bf5664, 0x1fc67135, 0x11063124, 0x16e39911, 0x04ad0aa0, 0x0c26561a, 0x100ab3c0, 0xfe7e67}}, + {{0x1b7ab649, 0x07916cae, 0x0c483479, 0x002e0e88, 0x1251f3b8, 0x070b4c24, 0x12e62302, 0x0cf4503b, 0x38aa69}}}, + /* 13*16^33*G: */ + {{{0x0cfffefa, 0x138ab134, 0x1946beb7, 0x10089ee0, 0x1af85101, 0x17c8a861, 0x049f5b7d, 0x194ea706, 0x91baf5}}, + {{0x1f7f6faf, 0x1e9b79a6, 0x1f4c0f71, 0x1de621cd, 0x13d92f4b, 0x14f893ee, 0x13af9765, 0x023268f7, 0x4e5cf}}}, + /* 15*16^33*G: */ + {{{0x0d33c546, 0x1e048bf4, 0x17b6bccb, 0x0ebf6650, 0x1ddd7825, 0x09b9f07a, 0x029f2cb1, 0x043967ef, 0x445841}}, + {{0x000b4fd4, 0x05368c38, 0x0b29cd98, 0x1e1479f6, 0x0da20852, 0x0f571c8d, 0x14e9dc89, 0x0efe7f0e, 0x308d93}}} + }, + { + /* 1*16^34*G: */ + {{{0x00eae29e, 0x17db7571, 0x138741c5, 0x069e5e1a, 0x04266c70, 0x0a9bd22d, 0x0cc7ae58, 0x13631d7e, 0x8c00fa}}, + {{0x0702414b, 0x1e952633, 0x18db1539, 0x15b5f503, 0x0c974c2f, 0x1a1d1b9b, 0x0686a770, 0x0cffd4a4, 0xefa472}}}, + /* 3*16^34*G: */ + {{{0x0bfd913d, 0x1fcab01f, 0x15327ab0, 0x0d01cddc, 0x08d2050a, 0x1d042615, 0x17e1d341, 0x14fd20fb, 0x36362a}}, + {{0x052e243d, 0x027cd756, 0x0cbeabf1, 0x017621ad, 0x02a82d83, 0x1221b86d, 0x1f54d058, 0x0ced9715, 0x48f278}}}, + /* 5*16^34*G: */ + {{{0x0d132896, 0x055d5fcd, 0x0f1b259f, 0x03c7756f, 0x1200dfcb, 0x16cb16ec, 0x180bca56, 0x0dbe6543, 0x448797}}, + {{0x0f685248, 0x0600d895, 0x1daa9e92, 0x081ab4c4, 0x01a3306b, 0x1483ba2b, 0x1f87bf26, 0x0c1a22b5, 0x27bd58}}}, + /* 7*16^34*G: */ + {{{0x1fa2670c, 0x040ab7b5, 0x189cf9b8, 0x01f05740, 0x10324740, 0x0e55419a, 0x0de22daa, 0x18517970, 0x4a4d3a}}, + {{0x16c1764d, 0x045cffee, 0x0a6fbb60, 0x00b2997e, 0x02b9d493, 0x188eef78, 0x093c5f9d, 0x0380308b, 0x70abb9}}}, + /* 9*16^34*G: */ + {{{0x0cb24aa7, 0x0cb57f12, 0x0d1714c3, 0x02118c72, 0x0fe18903, 0x17ec4ffc, 0x000b0eb9, 0x03215d23, 0x5f7b2d}}, + {{0x0a693d7d, 0x0bc03a1a, 0x1207431b, 0x1bd6e127, 0x07c47ce8, 0x1c051e73, 0x0accc28f, 0x00189fbe, 0x77036}}}, + /* 11*16^34*G: */ + {{{0x0f7fb8bd, 0x0c8de2f9, 0x19024290, 0x08c942bf, 0x086d87bc, 0x12736ca4, 0x0340abb0, 0x0a2673b2, 0x513974}}, + {{0x03908c0f, 0x04a5616c, 0x1e6356a0, 0x1865a7c7, 0x15c47faf, 0x1f7ed740, 0x0fcd2e23, 0x07c8ec87, 0xfcd714}}}, + /* 13*16^34*G: */ + {{{0x0e36ca73, 0x15ba48af, 0x0efcfb78, 0x10c9a6d7, 0x14887eac, 0x08895f80, 0x1ee2a90a, 0x1ac57f7b, 0xcf8316}}, + {{0x0ec25534, 0x1a490ca1, 0x035c43d6, 0x0c2b31b1, 0x0ca681c9, 0x0284486e, 0x15cf8e11, 0x11bd6bb3, 0x9feb5}}}, + /* 15*16^34*G: */ + {{{0x1752f97d, 0x0449beb5, 0x0d1d984f, 0x1df78ebe, 0x1a6165a2, 0x09433467, 0x127794e7, 0x13498976, 0x8610de}}, + {{0x1f1b1af2, 0x02bee6a0, 0x1550f820, 0x169b3ea8, 0x1f99e57a, 0x0ccd9299, 0x0ef24df3, 0x14056c61, 0xd31997}}} + }, + { + /* 1*16^35*G: */ + {{{0x00cb3e41, 0x0bfeefe3, 0x02e4b026, 0x1a109e61, 0x18ed3143, 0x076054f4, 0x0a7cf843, 0x1cd3ba90, 0xe7a26c}}, + {{0x0f2cfd51, 0x1454a10e, 0x03a0f883, 0x0d658084, 0x1bb18d0a, 0x00350d57, 0x012d1c6c, 0x0601f4f3, 0x2a758e}}}, + /* 3*16^35*G: */ + {{{0x1aee42db, 0x07cfe95f, 0x0c1c529c, 0x1778b68e, 0x0bfc1d9b, 0x176dc8f6, 0x0543f1ed, 0x1cfb36b2, 0xcc3427}}, + {{0x15d87bdb, 0x1114e008, 0x1c908b71, 0x0b975b1c, 0x1520010e, 0x1fe9fd90, 0x1a862178, 0x0834a438, 0xea2498}}}, + /* 5*16^35*G: */ + {{{0x1ed4a086, 0x1a1b3633, 0x071043bf, 0x0eb82b1d, 0x15cf4b1d, 0x02c2fde5, 0x1177b20f, 0x1759b308, 0x948f05}}, + {{0x1e2bca4b, 0x150c007c, 0x0fe8b468, 0x06514e38, 0x139411c2, 0x08533008, 0x08ce0bd1, 0x13ff6b45, 0x864ca8}}}, + /* 7*16^35*G: */ + {{{0x17542c21, 0x065f5365, 0x09930570, 0x13e9a51d, 0x16d43ae1, 0x1e22a28e, 0x0b24195b, 0x0c525233, 0x258419}}, + {{0x072bfabf, 0x1f5f18cb, 0x10ab5ece, 0x07430dc9, 0x113d5f3e, 0x0d52663a, 0x11200797, 0x03e39b64, 0xfcb35b}}}, + /* 9*16^35*G: */ + {{{0x0c1ecbf8, 0x1e230fa0, 0x1bb5f290, 0x13e1bd35, 0x0421f648, 0x1aa660f4, 0x14948aa5, 0x18826e78, 0x7e12cd}}, + {{0x10bed615, 0x0a2dc66d, 0x18767d67, 0x13ec3b1f, 0x11259c96, 0x0a6d5f26, 0x00dc50fe, 0x111111b9, 0x71284f}}}, + /* 11*16^35*G: */ + {{{0x14557d86, 0x1f3328e0, 0x199ffd05, 0x1dd88f1c, 0x1a6cf1cf, 0x08e53d02, 0x0a99dcae, 0x1fe546e8, 0x4b8ec2}}, + {{0x15167eb9, 0x0ecd8c8d, 0x10fda4af, 0x0be5de1f, 0x1ac5f28d, 0x0396f293, 0x1eac5290, 0x1fe0982a, 0xfde6c3}}}, + /* 13*16^35*G: */ + {{{0x0780763c, 0x15c169da, 0x195a4754, 0x14dabd24, 0x0c07e5f8, 0x1b6e34bd, 0x09094c90, 0x00e672c7, 0xfcd5c1}}, + {{0x18e851cb, 0x0a73a101, 0x1918e92d, 0x13645ce2, 0x0e38cb11, 0x06d9afb9, 0x1118edc8, 0x1c5caa45, 0x18ddab}}}, + /* 15*16^35*G: */ + {{{0x1d8ef686, 0x071df182, 0x09cb99af, 0x1c91e804, 0x06e53f68, 0x12ed7c13, 0x0f9488e2, 0x1dcb0879, 0x900f2c}}, + {{0x0121a8cf, 0x19d24b3f, 0x0455b541, 0x19bfe879, 0x1d110596, 0x0a8d89a4, 0x096b5871, 0x0abd8c08, 0x732ac1}}} + }, + { + /* 1*16^36*G: */ + {{{0x1e6b80ef, 0x0794f59e, 0x1e5093cf, 0x17972cfa, 0x0bdc571c, 0x006111de, 0x1b2348d5, 0x01dc6cc5, 0xb6459e}}, + {{0x1a71ba45, 0x185f85b0, 0x18d6cbfc, 0x075cda91, 0x01db3c4b, 0x0f8b72b3, 0x01b7876b, 0x0da0de7c, 0x67c87}}}, + /* 3*16^36*G: */ + {{{0x119888e9, 0x1ce793c9, 0x1122a2d0, 0x0574d7e4, 0x081673d1, 0x069814b3, 0x1b8b7798, 0x0ee75874, 0x1f90ea}}, + {{0x0f113b79, 0x17efe4bf, 0x0548b995, 0x0ea3fdcb, 0x196a8213, 0x09e938f5, 0x043a5605, 0x0f82bb54, 0x89be36}}}, + /* 5*16^36*G: */ + {{{0x1562222c, 0x02f7db79, 0x19bcb182, 0x0688f323, 0x152bade0, 0x15d699a5, 0x02b5b9c0, 0x09bdbffc, 0x13a4e5}}, + {{0x08200145, 0x058b3465, 0x12413023, 0x138aef5b, 0x09a52d4f, 0x017c0eb0, 0x004ecb2b, 0x09cb02dd, 0xc9d67d}}}, + /* 7*16^36*G: */ + {{{0x143b46bb, 0x1bf26e07, 0x12494950, 0x1a74c7f5, 0x15dbd12e, 0x1e02ec22, 0x0b747501, 0x17e46795, 0x61991e}}, + {{0x0c20a848, 0x047ac80e, 0x0bb363bd, 0x10e5394a, 0x1adf11ca, 0x1c38b37d, 0x124a54bc, 0x011e7fbc, 0x1c5e3}}}, + /* 9*16^36*G: */ + {{{0x121add3b, 0x12df1eee, 0x1c9f63df, 0x15289e8a, 0x026118b9, 0x0e6d868b, 0x0e1d240e, 0x1496f0fa, 0xea27ae}}, + {{0x168ce7dd, 0x1af148ed, 0x1386f9c6, 0x0425ad1c, 0x02f6278b, 0x0759192e, 0x1f795c8f, 0x1cdc8542, 0xc70ff1}}}, + /* 11*16^36*G: */ + {{{0x011ff757, 0x1457c5db, 0x13089b9b, 0x19d2e838, 0x0b6da9b4, 0x087c5b71, 0x1552ea40, 0x06ad6fff, 0x594651}}, + {{0x094d031a, 0x05337654, 0x0fff8eca, 0x1778f6ff, 0x006f9961, 0x1c680ae2, 0x1d401080, 0x019cbbe4, 0x361136}}}, + /* 13*16^36*G: */ + {{{0x036160b5, 0x1b12c51b, 0x19faf019, 0x0a7e48e1, 0x11ec0ccc, 0x17bcb804, 0x0a43a10e, 0x0722bee6, 0x16b26e}}, + {{0x18a1dc0e, 0x0312fdfa, 0x0e8fbe05, 0x0c7558e1, 0x054d4e13, 0x01a9231b, 0x1e2ed8d9, 0x0b4c605d, 0x60f56}}}, + /* 15*16^36*G: */ + {{{0x17b32db8, 0x0b269449, 0x11de47ce, 0x1dae93ec, 0x0ea85c91, 0x0a1e4216, 0x1e4c6fa8, 0x12b88ab3, 0x24b52}}, + {{0x0a64f760, 0x0a2a7d55, 0x16e06a56, 0x16d02240, 0x05be862a, 0x1410e62f, 0x0271edb8, 0x11eb7fe6, 0x609fef}}} + }, + { + /* 1*16^37*G: */ + {{{0x096943e8, 0x16d07ada, 0x1cf16977, 0x1e3f8cfc, 0x106231d6, 0x1a5508c7, 0x0101e4c8, 0x19050177, 0xd68a80}}, + {{0x0b133120, 0x0a642133, 0x114a568a, 0x1cf71ef0, 0x0e28b5b0, 0x0fc8bbd8, 0x1b40312c, 0x1ffe96b0, 0xdb8ba9}}}, + /* 3*16^37*G: */ + {{{0x0ca1c4f9, 0x0da1550c, 0x0df8a08d, 0x1dfc6995, 0x116f44f4, 0x1c1ed30f, 0x0a313102, 0x11e457ae, 0x7815f7}}, + {{0x1778bc15, 0x158f51b5, 0x1df47866, 0x085bcc2a, 0x0c35d5cb, 0x1e798a2c, 0x1da9f764, 0x1d19a735, 0xc1c601}}}, + /* 5*16^37*G: */ + {{{0x0e8c8530, 0x09370e1f, 0x03d3639b, 0x1bed03df, 0x06c6d512, 0x1e3200b5, 0x005db8dd, 0x19b41d88, 0xc39273}}, + {{0x198446c7, 0x0018787b, 0x1bb5c571, 0x1bf97b45, 0x1199850e, 0x09ca20e1, 0x123a7407, 0x084ae867, 0x8c41be}}}, + /* 7*16^37*G: */ + {{{0x037a26c1, 0x0f9205d9, 0x16fda94c, 0x18dcb181, 0x03b25166, 0x1218e0e8, 0x06c09d48, 0x08feb082, 0xda3174}}, + {{0x0cf74d6f, 0x08c1b767, 0x0a05497d, 0x106d8baf, 0x1d8b7d36, 0x00b3e12c, 0x11a748e1, 0x170febb1, 0x753b97}}}, + /* 9*16^37*G: */ + {{{0x1739dc49, 0x15b14549, 0x1d5580f4, 0x0725b4cd, 0x1231a239, 0x162845ff, 0x19b04192, 0x196055e1, 0x6a4be6}}, + {{0x12edd5cf, 0x13515cef, 0x1292934f, 0x1c569962, 0x08058ab7, 0x1371b07d, 0x1d65f705, 0x15455120, 0xf15d8f}}}, + /* 11*16^37*G: */ + {{{0x06987fac, 0x05f45062, 0x0a1bd9e6, 0x121f0c81, 0x18a3c8bc, 0x01301f64, 0x1c4d13a6, 0x13e275cf, 0x1f7c6}}, + {{0x19174c68, 0x1c8f39c0, 0x1daf098f, 0x1ebbc433, 0x0b6f9cb7, 0x01b7194d, 0x08b796c4, 0x07e6dfb4, 0x9d4ecc}}}, + /* 13*16^37*G: */ + {{{0x16daba4d, 0x099d0deb, 0x0c658987, 0x0bf61c40, 0x02bcb9c6, 0x1176ec7d, 0x0e072dc1, 0x002ec3fa, 0x557e94}}, + {{0x17a52316, 0x09ba50dd, 0x10d64294, 0x1371ebf4, 0x0bc86c5e, 0x0e7d0ae6, 0x1f811b4d, 0x074c03f4, 0x7a7e8f}}}, + /* 15*16^37*G: */ + {{{0x09f5341a, 0x1c7a97f9, 0x058dae00, 0x0f4658cd, 0x101419cc, 0x0a0753d8, 0x16a4eca7, 0x10433310, 0x3adada}}, + {{0x0586c6cc, 0x08ac049b, 0x17a3ef2d, 0x0da5cb68, 0x11017e9d, 0x1adf9b55, 0x1a7d54b8, 0x04513326, 0xbfea1e}}} + }, + { + /* 1*16^38*G: */ + {{{0x028d3d5d, 0x04acc07e, 0x11273a90, 0x055d72e6, 0x030b0961, 0x0138483d, 0x01094b70, 0x0fbecb90, 0x324aed}}, + {{0x16ab7c84, 0x1391257c, 0x0cca10e5, 0x027618fc, 0x01f4f192, 0x0061ad76, 0x1cbfc4c3, 0x0aee96c3, 0x648a36}}}, + /* 3*16^38*G: */ + {{{0x0fd53ed3, 0x0e48bac1, 0x095b33bd, 0x1ee9f73b, 0x17c49163, 0x105c98ef, 0x0ab56e3d, 0x1ab32cee, 0x20840b}}, + {{0x1a7a7132, 0x18a1ff28, 0x19c22661, 0x0f88e729, 0x0fac2548, 0x0a3b535d, 0x090d21ef, 0x12f9d830, 0xf29934}}}, + /* 5*16^38*G: */ + {{{0x08a35b35, 0x1e965dac, 0x028487b6, 0x0bb114b8, 0x0ebfd1ab, 0x0814f2c4, 0x06eef44f, 0x1ec1d667, 0xe6b6bf}}, + {{0x1c1007bd, 0x0b949edc, 0x1a6671f1, 0x16d93a77, 0x161ddfe3, 0x01f1c1ac, 0x0bcc99bd, 0x17a6601a, 0x1a5ff2}}}, + /* 7*16^38*G: */ + {{{0x00360dd3, 0x0a77c696, 0x14388243, 0x11506db0, 0x0e3bb47a, 0x1c043706, 0x06ca22c2, 0x0e8b7c93, 0xe05317}}, + {{0x1c24f87b, 0x15766c89, 0x040f70ac, 0x130fbd30, 0x0a01461b, 0x0ac15adb, 0x1ce73602, 0x0e34bb25, 0xdc1c3b}}}, + /* 9*16^38*G: */ + {{{0x1098dfea, 0x00a33316, 0x099e1e5f, 0x1967925d, 0x05e57fad, 0x12e9541d, 0x11678063, 0x074ef10d, 0xa8153b}}, + {{0x0e6d892f, 0x124d4efb, 0x16bd0562, 0x0bc1ee85, 0x13e03b1b, 0x0dce2bc2, 0x03f14f63, 0x0c8c3a0c, 0x2a4739}}}, + /* 11*16^38*G: */ + {{{0x0bcecfa5, 0x13f3bd24, 0x05aec082, 0x1ac5b436, 0x0da3b2a0, 0x14ae31c7, 0x176b7ad1, 0x1661fd95, 0x4f05c3}}, + {{0x15d37b53, 0x16681254, 0x06d2334b, 0x1dc863e0, 0x134b9447, 0x191b0aca, 0x09beb758, 0x1d4c07a8, 0x53a499}}}, + /* 13*16^38*G: */ + {{{0x084b96aa, 0x10f3b2c8, 0x0aaf3391, 0x130c6aa4, 0x1980ed02, 0x02f0d51d, 0x046f8990, 0x1733ecf5, 0xd9309a}}, + {{0x02b28a86, 0x136279be, 0x13fa5e3c, 0x0d93f75f, 0x0cb5fd3b, 0x0783313a, 0x155f5f84, 0x055369d8, 0x6ef99b}}}, + /* 15*16^38*G: */ + {{{0x1f8fcf0e, 0x1bdc682c, 0x1129beb3, 0x16dffbcf, 0x03411d65, 0x1a236f55, 0x14d6ea70, 0x14270ac5, 0x7d587c}}, + {{0x18bc9459, 0x00e0d04e, 0x08de0294, 0x072015a6, 0x16ad0c46, 0x0005b67e, 0x11849c8d, 0x00710609, 0xa7295c}}} + }, + { + /* 1*16^39*G: */ + {{{0x1d054c96, 0x145e9b9f, 0x1472a223, 0x08287751, 0x0e5dceec, 0x0fedf2ff, 0x187db547, 0x092339bc, 0x4df9c1}}, + {{0x0ad10d5d, 0x175d6036, 0x02124064, 0x0a0d9b85, 0x185d4b5d, 0x1a611d0e, 0x1ca01425, 0x0a2125b0, 0x35ec}}}, + /* 3*16^39*G: */ + {{{0x1def001d, 0x07912ed2, 0x06e89fbd, 0x1377ad31, 0x1b64b21f, 0x1e8e04f1, 0x12bc8382, 0x05b64fc5, 0xa549a3}}, + {{0x10624783, 0x0aed8d3f, 0x125c16b7, 0x083c54c5, 0x19456eb1, 0x01876c52, 0x1b2f7d33, 0x0f20db2c, 0x799b7a}}}, + /* 5*16^39*G: */ + {{{0x052ed4cb, 0x0d778f2e, 0x027b1681, 0x09bdf678, 0x12e6ec95, 0x05ecc1a9, 0x13448fc2, 0x061b40fd, 0x7e798f}}, + {{0x14bb9462, 0x0b8b303c, 0x07cde849, 0x06ae37ff, 0x0f057b17, 0x0aa4ef79, 0x120c106a, 0x189449b5, 0xd23dcc}}}, + /* 7*16^39*G: */ + {{{0x13630834, 0x0f9d07de, 0x16b019ff, 0x07e250c7, 0x08108846, 0x0f4b5d46, 0x1e0eb56e, 0x00062a28, 0x224fa2}}, + {{0x047a2272, 0x09e239be, 0x0943dd73, 0x05249d81, 0x109f53d6, 0x187d1c8e, 0x0970f12d, 0x065767db, 0xbbe54e}}}, + /* 9*16^39*G: */ + {{{0x183c19d7, 0x13b24e8a, 0x0b3d5eed, 0x16bc8b58, 0x08ef2bbb, 0x12e67211, 0x07904a68, 0x198c0147, 0xc2d4a0}}, + {{0x0507928d, 0x17945c16, 0x0d1725dc, 0x0095062e, 0x1260d268, 0x1dafbfa0, 0x0a535060, 0x1f38100c, 0x65ada0}}}, + /* 11*16^39*G: */ + {{{0x1c940c9a, 0x064056a5, 0x1d08cc21, 0x1e79c275, 0x1dc2113c, 0x02f13a26, 0x0c643956, 0x0fd860be, 0x2ec22a}}, + {{0x051e7a4d, 0x08ca7ecc, 0x08d6f6b3, 0x00a307b3, 0x07feb124, 0x127a814e, 0x05a130b8, 0x0d1bc66f, 0x8b1da4}}}, + /* 13*16^39*G: */ + {{{0x1d683eeb, 0x138772fe, 0x034c4cea, 0x0dd67141, 0x0b8f33e3, 0x1b292842, 0x13b2ac6b, 0x0e71f351, 0xafc669}}, + {{0x10cd4509, 0x0f14e559, 0x1b77f724, 0x1756aa4b, 0x19c16570, 0x0e3fe511, 0x1d4af0d6, 0x12edba44, 0x2c21}}}, + /* 15*16^39*G: */ + {{{0x176f4293, 0x1100fc3d, 0x0f144e7a, 0x12f16aca, 0x1282e10e, 0x04679b85, 0x0c24486f, 0x0b53e686, 0xd2557b}}, + {{0x1282740a, 0x0d8c3d12, 0x101697c7, 0x16d071bc, 0x0d21fe34, 0x178375a5, 0x1fc049a0, 0x086abc84, 0xa787b3}}} + }, + { + /* 1*16^40*G: */ + {{{0x0c1f98cd, 0x1fe4ce45, 0x1fc0c232, 0x09120a9a, 0x06021523, 0x054e0e63, 0x01c3ebb6, 0x150948e9, 0x9c3919}}, + {{0x14fc599d, 0x13f2f01e, 0x193239af, 0x064deed8, 0x0e641905, 0x0225f930, 0x155d613c, 0x01e949bb, 0xddb84f}}}, + /* 3*16^40*G: */ + {{{0x0fb64db3, 0x1dcc6a9c, 0x1754e105, 0x1bc99473, 0x1b8d6a7e, 0x1c1fdf29, 0x12dd02ee, 0x124537b9, 0xc11423}}, + {{0x1c0259be, 0x118674ff, 0x1159f478, 0x0b01209a, 0x18bd1a87, 0x06f27f4b, 0x1f0a973b, 0x1b8b690d, 0x1237f6}}}, + /* 5*16^40*G: */ + {{{0x03081e46, 0x16f6c1a0, 0x11567a87, 0x044318aa, 0x034713a5, 0x0e160c93, 0x089020b6, 0x1f0634ee, 0x6c5b4b}}, + {{0x0bfbcd70, 0x08fce5c0, 0x108a98bb, 0x019f04d5, 0x1e47841d, 0x1c31e715, 0x10bec8d1, 0x0e2924da, 0xcb0513}}}, + /* 7*16^40*G: */ + {{{0x064dcd4b, 0x0572d762, 0x04704937, 0x018fab32, 0x10a450c3, 0x0332e558, 0x1792d59c, 0x0acce195, 0xe1e9a8}}, + {{0x1b041f2c, 0x085b12f5, 0x085aca4b, 0x09a33559, 0x177927f4, 0x01accd92, 0x14c6deb1, 0x12a88ab8, 0x562b0a}}}, + /* 9*16^40*G: */ + {{{0x0badd73c, 0x02c3b7f1, 0x0992df40, 0x139bb205, 0x014208fd, 0x1a72176e, 0x0265de29, 0x0af5a236, 0x51b21a}}, + {{0x0b36d8d1, 0x1bea570f, 0x11cd2e9b, 0x00261e51, 0x01cfa6c2, 0x03f80e96, 0x0f975528, 0x020003fa, 0x7930}}}, + /* 11*16^40*G: */ + {{{0x1b09f34b, 0x0bae85b9, 0x1319b39b, 0x10e7cc11, 0x19d61e58, 0x114b79f9, 0x1e6186ad, 0x14c76396, 0x9701f3}}, + {{0x00df5793, 0x06e42866, 0x1731e52b, 0x097872ff, 0x08337710, 0x18da98ab, 0x1b4575c0, 0x177195e1, 0x3dd44b}}}, + /* 13*16^40*G: */ + {{{0x1f1e2f46, 0x0e73111d, 0x09de0c05, 0x01ee3d0e, 0x03c57527, 0x0970206b, 0x1b311156, 0x03a593cc, 0xa036b4}}, + {{0x1effb349, 0x198f134a, 0x1c2c7d3d, 0x01c5059f, 0x0b08d068, 0x1b5523cf, 0x0cf5f7c7, 0x14007d2d, 0xc3bf91}}}, + /* 15*16^40*G: */ + {{{0x0c4cea08, 0x06c5c81c, 0x03a8876f, 0x16b1741c, 0x04652654, 0x108a9a00, 0x1141bd29, 0x1b7549d1, 0x6a85fa}}, + {{0x1862f4f3, 0x0cef672c, 0x15c86da8, 0x0e349687, 0x06230b42, 0x19e0a47f, 0x16754c64, 0x00975c8c, 0xb646}}} + }, + { + /* 1*16^41*G: */ + {{{0x00a959e5, 0x1109c109, 0x04753316, 0x02927517, 0x006bb91e, 0x0f940ec7, 0x1f7e3781, 0x0163ba25, 0x605717}}, + {{0x0385a2a8, 0x04cdf499, 0x1893197a, 0x02a5787d, 0x1f262465, 0x116d7b8e, 0x001eb766, 0x164d4d49, 0x9a1af0}}}, + /* 3*16^41*G: */ + {{{0x171c032b, 0x0a6d0b14, 0x0bf72603, 0x16cd142f, 0x166c5ff6, 0x0dafefe3, 0x0980f744, 0x1f9adc00, 0x71eba8}}, + {{0x1668359f, 0x1d5ad470, 0x12d1d579, 0x0635a2ee, 0x0bb7f719, 0x028b7aa6, 0x0e77bd98, 0x0c496c3a, 0xd2ff12}}}, + /* 5*16^41*G: */ + {{{0x0a03a61c, 0x03723a29, 0x01c15d34, 0x10d1e8d2, 0x09dd0507, 0x1a215d55, 0x148cb285, 0x00b66493, 0x855ec3}}, + {{0x065dfc07, 0x0fe37556, 0x1f912597, 0x05ee9d42, 0x0fb4ed33, 0x05ffcda1, 0x105fd50f, 0x05d8be03, 0xdd85d}}}, + /* 7*16^41*G: */ + {{{0x1f32d706, 0x00605240, 0x1a819e2c, 0x119948e8, 0x1bfa2061, 0x094d184a, 0x0fc7c543, 0x0d57567f, 0x3ce448}}, + {{0x1c7fd9e4, 0x05b9b1bf, 0x187a27d0, 0x02ac879a, 0x14906edd, 0x08235884, 0x014a23bf, 0x11b55c6f, 0xe77540}}}, + /* 9*16^41*G: */ + {{{0x191cd3fb, 0x0da065db, 0x0a6f9a1b, 0x1467fb2e, 0x044eb4a2, 0x0190c7c4, 0x1febc0b8, 0x0287e9c6, 0x11ccc5}}, + {{0x15160d86, 0x09b8b5d2, 0x174d1caa, 0x163dfa59, 0x0c239fa0, 0x112249c6, 0x077ad4a3, 0x05520562, 0x4aa56b}}}, + /* 11*16^41*G: */ + {{{0x018f7552, 0x03dc88cb, 0x0153eb0e, 0x02271730, 0x182ddbd4, 0x1bba7c11, 0x11bd0ee5, 0x02fca293, 0x250bb}}, + {{0x1510b14d, 0x18424b11, 0x0f5bc78f, 0x00de7866, 0x1d817da0, 0x1efbaff4, 0x0208d0b5, 0x1f9377d0, 0x731930}}}, + /* 13*16^41*G: */ + {{{0x1f725d12, 0x0e89f49c, 0x0d7d1d41, 0x0c8577b9, 0x02fbfd94, 0x1ce70501, 0x1f4ead28, 0x111668cf, 0x1a749c}}, + {{0x03ac56e4, 0x09b28a69, 0x0436a9c0, 0x0410d313, 0x13d8f607, 0x1f3ae157, 0x18b3d162, 0x12ae7d81, 0x7e91d1}}}, + /* 15*16^41*G: */ + {{{0x09fae458, 0x10824729, 0x1bb25ff5, 0x14b884ec, 0x17b328b0, 0x0ab52efd, 0x06304274, 0x0b7c1f04, 0xc75068}}, + {{0x1757b598, 0x00b420ca, 0x165468ac, 0x1b94a066, 0x0c7b40a5, 0x1a0a6339, 0x1817ed4b, 0x1f19f243, 0xead795}}} + }, + { + /* 1*16^42*G: */ + {{{0x0cb94266, 0x0d34b9f7, 0x1537c4ac, 0x1de1f74f, 0x1a31880c, 0x1cd228c6, 0x10450850, 0x11c47410, 0xa576df}}, + {{0x01b28ec8, 0x145f08d7, 0x05367cfb, 0x1c214fea, 0x0d82c432, 0x0bd7f2c6, 0x02cb24ae, 0x041cecc8, 0x40a6bf}}}, + /* 3*16^42*G: */ + {{{0x0d9ed6c1, 0x14575ac6, 0x1564f5ad, 0x1ce8b787, 0x0dd0ec24, 0x00c3b82f, 0x14fa02ff, 0x0db96e9e, 0x32833}}, + {{0x18fafeee, 0x16375f37, 0x12d252b7, 0x17e9be4b, 0x17c8c265, 0x0ca1d106, 0x1ca311b5, 0x07025fb3, 0x71a898}}}, + /* 5*16^42*G: */ + {{{0x1235983a, 0x0cd4d469, 0x0ef3aca4, 0x14206e02, 0x01531e38, 0x0936b87f, 0x1153718e, 0x15d17223, 0xce4f4e}}, + {{0x0d3cdecf, 0x07eb58c8, 0x0fdd02bb, 0x18ca451d, 0x07543526, 0x10124f38, 0x0eecfab7, 0x0e78721f, 0xf3c9f9}}}, + /* 7*16^42*G: */ + {{{0x15b0e6c9, 0x16d55b32, 0x1b932269, 0x1ff39ef0, 0x0bcbddb5, 0x07d9b6fc, 0x0889e38a, 0x14a9730c, 0x4dbebf}}, + {{0x1eb2cc25, 0x0a53c2aa, 0x1413beba, 0x06236578, 0x029f3589, 0x11373711, 0x0bb7d169, 0x16079227, 0x10fee7}}}, + /* 9*16^42*G: */ + {{{0x05857295, 0x0700d08d, 0x10cfc059, 0x11c8fe06, 0x0a12069c, 0x08c7e50e, 0x10862cb8, 0x017fde8b, 0xa42a24}}, + {{0x0a7eb9c1, 0x159bbff6, 0x1464e555, 0x038459a2, 0x1a4c427a, 0x1915926e, 0x15159e9a, 0x1e4c200b, 0x3aa0b3}}}, + /* 11*16^42*G: */ + {{{0x0fcdc098, 0x1107faab, 0x191a00c8, 0x15c01ed5, 0x099c1550, 0x0fc36062, 0x0899e9fc, 0x05f2df64, 0x34e12b}}, + {{0x0a7474e2, 0x0658d6f3, 0x0620fd99, 0x1ea261e3, 0x172db04d, 0x05e420bc, 0x0c8b65d3, 0x1bbaf6ba, 0xa64ac2}}}, + /* 13*16^42*G: */ + {{{0x0f173b92, 0x06b75af4, 0x07edd847, 0x1ce5e82d, 0x165683b7, 0x0d10c7a6, 0x07ca6f8c, 0x081b3772, 0x10f4d2}}, + {{0x033146c2, 0x0810036b, 0x01ab6df2, 0x16ed3a29, 0x108ba90b, 0x12d2d19c, 0x0eb4846c, 0x12a122ea, 0x850e2d}}}, + /* 15*16^42*G: */ + {{{0x08d84958, 0x137e8ecd, 0x0b3172bb, 0x03bd62d9, 0x0cc866a1, 0x0dcbb6a0, 0x1f9d27c6, 0x016d36ce, 0xe846e8}}, + {{0x1882cf9f, 0x062323db, 0x18306990, 0x03466ce3, 0x0b76fad5, 0x0c8823cc, 0x1895076f, 0x1f91298f, 0xa29cb8}}} + }, + { + /* 1*16^43*G: */ + {{{0x1e58ad71, 0x1bb1c44d, 0x068e8823, 0x01a3eb9f, 0x08c38bb3, 0x1f4b14ef, 0x0f8c2817, 0x11851bd8, 0x7778a7}}, + {{0x1d9f43ac, 0x1a89fe0f, 0x092b158e, 0x070823fe, 0x1580087b, 0x0709797f, 0x08bfdc26, 0x1356b4b6, 0x34626d}}}, + /* 3*16^43*G: */ + {{{0x1319c869, 0x1be37571, 0x07ac9c0b, 0x13f2baec, 0x0acdc18a, 0x1c8117e6, 0x1f234060, 0x0bb302e7, 0x301804}}, + {{0x12b856f0, 0x0063b64e, 0x0f669eff, 0x15099494, 0x02e3bca2, 0x121906b1, 0x1edbe198, 0x0f04a076, 0xac5fc5}}}, + /* 5*16^43*G: */ + {{{0x05ed29b5, 0x0334c37d, 0x0ab746d3, 0x0616c0e2, 0x1c885f58, 0x13edcd31, 0x1bcd0ead, 0x16c3dcaf, 0x322881}}, + {{0x1cd15ad2, 0x1a789373, 0x1b9d813b, 0x075d5729, 0x131e1ca8, 0x18cefa0a, 0x113ac442, 0x1082f406, 0x167702}}}, + /* 7*16^43*G: */ + {{{0x06c96100, 0x1fd4203c, 0x1a72398e, 0x0602354d, 0x1dbcca16, 0x0ecd96f9, 0x0e7fed0f, 0x07581f63, 0x3f3847}}, + {{0x12624707, 0x0f1560df, 0x1d7c6f3c, 0x0e38f816, 0x19ce5665, 0x02231783, 0x0e5494d3, 0x0abeba80, 0x70c69c}}}, + /* 9*16^43*G: */ + {{{0x1d22d2ac, 0x1a637637, 0x12ab3808, 0x1bfc24db, 0x1df2f10d, 0x00704bc2, 0x1db72d0f, 0x18bfa4f4, 0x288113}}, + {{0x0f42a268, 0x00f5aafc, 0x12323f42, 0x07a8942a, 0x16137ddc, 0x1b93064b, 0x1723c81d, 0x002b1f78, 0xa1a7eb}}}, + /* 11*16^43*G: */ + {{{0x045f8ea8, 0x05d406e9, 0x134a4035, 0x0491c72c, 0x19fe5d17, 0x06caeb88, 0x08a954fd, 0x001908c7, 0xf963a2}}, + {{0x19bc99eb, 0x1e2afd82, 0x02d82092, 0x11e46b3b, 0x027208bb, 0x11180ffa, 0x0f028edc, 0x04d18ff0, 0x9c8594}}}, + /* 13*16^43*G: */ + {{{0x0606a315, 0x10d44189, 0x1a58eb67, 0x04c0e5e4, 0x0097e407, 0x05952c87, 0x069fe636, 0x099fee1b, 0xa5d922}}, + {{0x1e3b68d1, 0x1ab099ac, 0x0469f274, 0x1a1a68fa, 0x00de9ed4, 0x0355ebcc, 0x096cd0cc, 0x0007641b, 0x87328b}}}, + /* 15*16^43*G: */ + {{{0x06231493, 0x06dbdaa0, 0x131351a7, 0x02350619, 0x1e6a4964, 0x120e8072, 0x0d813ad3, 0x05c36e78, 0xf1fe98}}, + {{0x158848c1, 0x0b54cd33, 0x17fc3406, 0x07f668dc, 0x199d3f17, 0x1e102fbe, 0x177085b4, 0x1d5db349, 0x2e2019}}} + }, + { + /* 1*16^44*G: */ + {{{0x06d903ac, 0x04f6d4e0, 0x0b5f972c, 0x12c4e9cb, 0x0fd2ed5f, 0x0fe9873d, 0x01118dca, 0x0bdcc6f5, 0x92895}}, + {{0x1bcd091f, 0x08c0749a, 0x0a360ff1, 0x1a4ddf51, 0x095eeac3, 0x0509849d, 0x0aa09ede, 0x0007a7e8, 0xc25621}}}, + /* 3*16^44*G: */ + {{{0x1874b839, 0x088943ab, 0x0f4ad060, 0x022b672a, 0x0b6aebe4, 0x186fd918, 0x16a014f7, 0x03f81c3c, 0x3e03b8}}, + {{0x1c0594ba, 0x060e72b3, 0x0ad6e368, 0x0b8be1fb, 0x18f667de, 0x1303ab8c, 0x1d0b113d, 0x0c7bfe0f, 0xd13ae1}}}, + /* 5*16^44*G: */ + {{{0x0357a513, 0x11fbc734, 0x0cc08fce, 0x037a268b, 0x122c5f15, 0x1141d514, 0x04b358be, 0x16f45e89, 0xe662c0}}, + {{0x0017d07e, 0x095100e5, 0x14e36246, 0x06b9ac4a, 0x1a419d80, 0x11045090, 0x148c176b, 0x079cc248, 0xab0b19}}}, + /* 7*16^44*G: */ + {{{0x1f37d242, 0x0cafbf7e, 0x07052c12, 0x1fd94c0f, 0x1587dc29, 0x1163e5f1, 0x1b2e10e1, 0x1639299e, 0x40bf80}}, + {{0x06405088, 0x08ec13cd, 0x0f4d560f, 0x043d7485, 0x0fe12743, 0x1f4d8d93, 0x0bc13d4f, 0x06bb0ad5, 0xb579dd}}}, + /* 9*16^44*G: */ + {{{0x195a3558, 0x17959b22, 0x0d29fcae, 0x0e3f0bc4, 0x159f6ac0, 0x0bc09c6d, 0x09c201be, 0x12ec03b9, 0x3d14fe}}, + {{0x0443df4c, 0x156d9d63, 0x1075c9f1, 0x0145c28f, 0x16e1482e, 0x1498edfa, 0x07be3ca6, 0x1add08d0, 0x16c6bd}}}, + /* 11*16^44*G: */ + {{{0x02b1fc24, 0x0f4fad6c, 0x0fdd5c3b, 0x11b038fc, 0x04865252, 0x16269649, 0x14947306, 0x081d05cc, 0xdd6fa5}}, + {{0x0e9b74ca, 0x1218e230, 0x1cc88c12, 0x01bcd7da, 0x17e77ec1, 0x18f5f8b2, 0x01bf8d9b, 0x0fd63a63, 0x67e62b}}}, + /* 13*16^44*G: */ + {{{0x1dd08e02, 0x0f548ac9, 0x0b7c0a20, 0x0a8f6ffb, 0x11e80108, 0x0a4cd51e, 0x15e03e1a, 0x1505bcab, 0x13fa2d}}, + {{0x1cb03410, 0x12aa0ee1, 0x090ae5f6, 0x095f7633, 0x032c7e64, 0x0b1035da, 0x09c8c4cd, 0x1608aabb, 0x136338}}}, + /* 15*16^44*G: */ + {{{0x144ee41a, 0x0119d5cc, 0x1f5a69ab, 0x16adba76, 0x08282879, 0x085b3963, 0x0910fdf0, 0x0a3a78e1, 0xd06c48}}, + {{0x0b295e6f, 0x18fc274c, 0x18bb894b, 0x170868c2, 0x030919b7, 0x166a7a7b, 0x02b6eec2, 0x0980b09a, 0x5815fd}}} + }, + { + /* 1*16^45*G: */ + {{{0x03d82751, 0x1d573a8b, 0x0b4d5149, 0x0b69520f, 0x1b285564, 0x1279d071, 0x0424e641, 0x1e7d8db6, 0x85d0fe}}, + {{0x0eb1f962, 0x1611bd12, 0x1dccc560, 0x0ea3d2d0, 0x0f5663e8, 0x04b72c16, 0x102f8a75, 0x10827471, 0x1f0364}}}, + /* 3*16^45*G: */ + {{{0x0cde4cf3, 0x0caa830f, 0x02819aae, 0x01ca6a8f, 0x19ae7934, 0x169368ae, 0x0b0ef9f0, 0x09582284, 0x384dab}}, + {{0x052d0566, 0x1e3cb591, 0x146e9ced, 0x0614672e, 0x0c6f01f4, 0x16b6d15a, 0x090efed3, 0x179a3739, 0xd6e3c5}}}, + /* 5*16^45*G: */ + {{{0x1e5238c2, 0x0579f490, 0x03b2e2e6, 0x0abeb870, 0x0ed48403, 0x1085a741, 0x16a906c5, 0x01d6fa82, 0x14f0ec}}, + {{0x12f07922, 0x14351a3c, 0x0124e75b, 0x1801b006, 0x0747fd25, 0x039f1c21, 0x1602487f, 0x07ba906b, 0xab12d5}}}, + /* 7*16^45*G: */ + {{{0x1543e94d, 0x1b1a977e, 0x1e638623, 0x06054ead, 0x00ddadd1, 0x1a33c52d, 0x01fb1070, 0x176f0585, 0xeb42f3}}, + {{0x05924d89, 0x02acef22, 0x035b5090, 0x108d1bcc, 0x1fb774cd, 0x0eab97e6, 0x04b72683, 0x00e9e4bb, 0x234a6d}}}, + /* 9*16^45*G: */ + {{{0x1e19aaed, 0x19272dab, 0x199cc9c0, 0x1759bd18, 0x0a920459, 0x0017b703, 0x0366a7bb, 0x194a2d04, 0x1cf138}}, + {{0x092f400e, 0x09b752eb, 0x11dffef0, 0x1ddf1fdf, 0x1de17479, 0x195335b6, 0x0e197d0d, 0x1e62e38c, 0xd6ffda}}}, + /* 11*16^45*G: */ + {{{0x16a8aa39, 0x1b6074fd, 0x1e3eb157, 0x0cc6f694, 0x190d937a, 0x104b424c, 0x104b21d6, 0x17cbe81a, 0xb58686}}, + {{0x0b493c1f, 0x1e3c9ae9, 0x16cd1ee3, 0x1b5f31cd, 0x0a91dabb, 0x1c6a2a60, 0x10b05251, 0x086498f1, 0x5632d5}}}, + /* 13*16^45*G: */ + {{{0x103b4cc5, 0x148f5f1d, 0x071df0bb, 0x106374b4, 0x1a802572, 0x1e27f3f9, 0x10ad9ed6, 0x160d7179, 0x5fc19d}}, + {{0x05b57c28, 0x1d9cfdc3, 0x021fb128, 0x0dea0798, 0x05ef4927, 0x09c7cd1d, 0x1f19bb88, 0x181d9318, 0xec8e84}}}, + /* 15*16^45*G: */ + {{{0x0cb38cb5, 0x1a5c2bea, 0x0e22522e, 0x16ffbe9a, 0x0ea1be10, 0x05207e9f, 0x0a277aea, 0x01a85dbc, 0xb88fb7}}, + {{0x1965f3d7, 0x1dfd3ab2, 0x0be31c65, 0x1e7c244f, 0x1a8e24d4, 0x1dcca59a, 0x0a0180d2, 0x15a8dd46, 0xd6c736}}} + }, + { + /* 1*16^46*G: */ + {{{0x0526087e, 0x1aa02412, 0x16880c23, 0x16db1105, 0x0b85dfdf, 0x1b020bcc, 0x1a5f0726, 0x19d2fdd9, 0xff2b0d}}, + {{0x10c29907, 0x04a8f00f, 0x038b3acb, 0x0fdadf72, 0x07936c7b, 0x026e2a68, 0x08622bd3, 0x1fdea497, 0x493d13}}}, + /* 3*16^46*G: */ + {{{0x19d681f9, 0x0c82a7f3, 0x03fae7f1, 0x1c1ddf59, 0x094b066c, 0x1f92f016, 0x0c2222df, 0x1e4eebe4, 0xc745fd}}, + {{0x1bbb1247, 0x018b9a1b, 0x1f5171d8, 0x17a66b8c, 0x018678cd, 0x1ca63874, 0x179e29c4, 0x1e5ed73c, 0x590222}}}, + /* 5*16^46*G: */ + {{{0x15cd0ea3, 0x10267769, 0x12b12057, 0x08f1d041, 0x0e7f2b34, 0x0f2f5b39, 0x142c9e96, 0x1e752ea0, 0xabb279}}, + {{0x1c307bce, 0x1849899b, 0x00bced91, 0x0ed20b3c, 0x18ed47c9, 0x1f060183, 0x1c367ed2, 0x0777e2f2, 0x5dee10}}}, + /* 7*16^46*G: */ + {{{0x1bc9ee3e, 0x017179f8, 0x19ce0b17, 0x1f4352c7, 0x1ed11ea9, 0x1553a133, 0x00a09feb, 0x016b3f8d, 0x3f8115}}, + {{0x199aae06, 0x0756d862, 0x16a0580f, 0x0765b9f9, 0x15662762, 0x1f59e23c, 0x00b519c6, 0x0d1fb7f5, 0x19c88a}}}, + /* 9*16^46*G: */ + {{{0x18e4a007, 0x0b8df7d7, 0x0ecd62d8, 0x19dd9e11, 0x0c7ec15e, 0x1d19d52b, 0x179a5652, 0x05ba0105, 0x5cf813}}, + {{0x1068b883, 0x131f8484, 0x071ffa33, 0x08df2d8f, 0x03df6c89, 0x00ac4246, 0x0837d2b5, 0x0b81ac3f, 0xb45aee}}}, + /* 11*16^46*G: */ + {{{0x06c2d4a7, 0x0ab7f3d9, 0x13ffec42, 0x06df2677, 0x04ed21bc, 0x19cb9e20, 0x125194f8, 0x09a1a974, 0xb6d5fe}}, + {{0x1ae86371, 0x0c6e73f1, 0x178f3204, 0x16fc9cde, 0x1fd8e745, 0x1c904eff, 0x1b0537f3, 0x1427577a, 0x47f373}}}, + /* 13*16^46*G: */ + {{{0x1c66dd33, 0x0499b117, 0x171db714, 0x1f791fe3, 0x1b022ea8, 0x0d8a8014, 0x021c1aec, 0x180cd9eb, 0x61c8bb}}, + {{0x16f10bfa, 0x1ddd4f9d, 0x00832328, 0x020dd585, 0x1d3fb6a5, 0x0cca5cc2, 0x1c0d119a, 0x0473ca9e, 0x93599e}}}, + /* 15*16^46*G: */ + {{{0x1d6b2ff8, 0x002dbe66, 0x01b23ea6, 0x066d82e5, 0x1bdf1876, 0x1a9b9f61, 0x01461f27, 0x14ae84cf, 0x94e32b}}, + {{0x0ce1af3e, 0x0ea42aa9, 0x1aff84eb, 0x15e084a4, 0x19e8cb33, 0x12443316, 0x13864bc7, 0x11687b40, 0xd1b44}}} + }, + { + /* 1*16^47*G: */ + {{{0x1856e241, 0x0072f167, 0x15b74a1e, 0x03dc2919, 0x1212b57f, 0x1973180d, 0x03aa7b4a, 0x1c963d10, 0x827fbb}}, + {{0x0ec293ec, 0x102db45d, 0x040c59b5, 0x0f4c630d, 0x112687ff, 0x19633e8e, 0x0c2dc6fb, 0x12478e4f, 0xc60f9c}}}, + /* 3*16^47*G: */ + {{{0x1bb80fa7, 0x1a242e59, 0x0104e218, 0x0fb4d76e, 0x0819f3aa, 0x1035e990, 0x0bef0346, 0x03ec6118, 0x857e3}}, + {{0x09366b2d, 0x0cc108f8, 0x15c05aaf, 0x1c6e0879, 0x17147172, 0x064e8ee5, 0x1c824b5f, 0x08475c02, 0xf64393}}}, + /* 5*16^47*G: */ + {{{0x09c70e63, 0x0e8161d0, 0x14f525bd, 0x1716f1ce, 0x0672e9cb, 0x032abb25, 0x0010d517, 0x1d4ad7ac, 0x28aacc}}, + {{0x1057da4e, 0x0f81c417, 0x13687a2e, 0x18b39c88, 0x0ebb7f5f, 0x0b33e3b4, 0x18559ea2, 0x05df0341, 0x2b6932}}}, + /* 7*16^47*G: */ + {{{0x13e674b5, 0x00ee297b, 0x0182ab18, 0x11ed39ce, 0x18a4f92d, 0x1964de75, 0x19851776, 0x04b40ab4, 0xa2f3b6}}, + {{0x0e937941, 0x049c6470, 0x0cfe94ec, 0x05f462f8, 0x07c4b922, 0x05487995, 0x02ba0011, 0x0b2c298d, 0x620ea1}}}, + /* 9*16^47*G: */ + {{{0x191eb056, 0x1b00b18e, 0x13f4e1b1, 0x05dfb71d, 0x115f5a00, 0x1ae351fa, 0x048c7662, 0x193d55cb, 0x3c4f83}}, + {{0x005cecab, 0x012c49ed, 0x13dae1dd, 0x056a8903, 0x07880198, 0x12b9e1d9, 0x0da8ceb5, 0x00ea2951, 0x944790}}}, + /* 11*16^47*G: */ + {{{0x1d86dfa9, 0x0830fedd, 0x0e64e9c6, 0x11694813, 0x03baadc3, 0x0f01f408, 0x1f538a70, 0x0511532c, 0xaff8e1}}, + {{0x01d12681, 0x1881e1b6, 0x067e71c1, 0x02db5288, 0x153f4f91, 0x15d50fe7, 0x10ff4f4f, 0x166426ef, 0x8d8b4b}}}, + /* 13*16^47*G: */ + {{{0x189ba9c1, 0x07939b5c, 0x074ce38a, 0x1ef94b41, 0x0e579e40, 0x01315767, 0x02cfa116, 0x08a51b80, 0xd3fb78}}, + {{0x0b51b267, 0x10dc46ff, 0x046b7801, 0x19dbab80, 0x10fe6341, 0x102bac5b, 0x139f29f2, 0x069df4d6, 0xf894d4}}}, + /* 15*16^47*G: */ + {{{0x0f2bb909, 0x0d4b60e8, 0x16636667, 0x0204f8a6, 0x07d7f639, 0x14c41c8c, 0x0a23fd1c, 0x01c15935, 0x4ec930}}, + {{0x04cf4071, 0x0451c1fd, 0x0b0e09ee, 0x1c2d041b, 0x049bad52, 0x0e228c26, 0x13717203, 0x00d7c360, 0x782ba1}}} + }, + { + /* 1*16^48*G: */ + {{{0x0120e2b3, 0x19dac7d1, 0x11fe6a9f, 0x11fb9cfe, 0x0e5217a5, 0x0571a673, 0x16eb9ef9, 0x1e43ea37, 0xeaa649}}, + {{0x1a5ad93d, 0x03d2982d, 0x0fdf9675, 0x0d72cbe2, 0x1aa5a01a, 0x007c4c3c, 0x00eb1a6a, 0x1dab7776, 0xbe3279}}}, + /* 3*16^48*G: */ + {{{0x1f2e070d, 0x0c1fe9d1, 0x0a9aa63d, 0x156e398a, 0x047e229a, 0x18e1dc28, 0x0affd21c, 0x1d2085e9, 0x4b72a5}}, + {{0x096dd780, 0x025d4177, 0x05230f79, 0x08cbbba5, 0x13c10b0b, 0x1dd9b687, 0x073d809d, 0x09c3ad5c, 0x599e1d}}}, + /* 5*16^48*G: */ + {{{0x0a02591c, 0x0e73fec2, 0x1449687a, 0x0a932cb0, 0x1fd613ef, 0x1fdf5af0, 0x038a169a, 0x1f8ca739, 0xa9fc93}}, + {{0x09bec2dc, 0x0856ef7b, 0x13dc94de, 0x111882bf, 0x165e5ca8, 0x00bd0d48, 0x1c5cfa13, 0x073b8a70, 0x9c2ce7}}}, + /* 7*16^48*G: */ + {{{0x0d968b59, 0x08037071, 0x12ef0b84, 0x05175c27, 0x1027709a, 0x1d60904d, 0x1c29a9f5, 0x0f834df3, 0xc94001}}, + {{0x0de572fb, 0x17ebb204, 0x0432723f, 0x08596c87, 0x1742ce28, 0x10dfd2da, 0x18804ee2, 0x0a019370, 0x39d922}}}, + /* 9*16^48*G: */ + {{{0x126b3332, 0x143999ab, 0x1b9779a8, 0x0711a0e7, 0x1f8e0310, 0x09d2fb85, 0x0093b19e, 0x13afdda0, 0x1f84bb}}, + {{0x14e8d52e, 0x0a214518, 0x1b70e895, 0x199c5a86, 0x1edf0c2b, 0x013fbadc, 0x1b30951f, 0x00e57953, 0xee726d}}}, + /* 11*16^48*G: */ + {{{0x0defa98e, 0x06d52a56, 0x0b09e657, 0x1088d023, 0x1e9c7724, 0x0abd9cc8, 0x1341b2a0, 0x112128bf, 0xf13e0}}, + {{0x1e286767, 0x0453bb4d, 0x13ab3370, 0x1ce0bc2d, 0x162db287, 0x1c5853d9, 0x1140d78f, 0x1e2ec9cf, 0xadd521}}}, + /* 13*16^48*G: */ + {{{0x09f59b6b, 0x0f0e01df, 0x02238be9, 0x0718c783, 0x026d3e9b, 0x050e96ac, 0x11f6cdca, 0x14aa3bbd, 0xdde191}}, + {{0x06cb1410, 0x156cb149, 0x0553fb3d, 0x0e7177ce, 0x0e14e8b5, 0x0beb0e29, 0x172f829d, 0x0f00504e, 0x5b2bfb}}}, + /* 15*16^48*G: */ + {{{0x09c6b699, 0x1462afee, 0x191a1c6d, 0x1eae6ad7, 0x01682a86, 0x0bdfcbda, 0x1de9685b, 0x05ddb06d, 0x5fab01}}, + {{0x01c6c3aa, 0x0b990a96, 0x020d466c, 0x1622ffd5, 0x02f7b90a, 0x1a08986b, 0x0513a7ae, 0x0e14787a, 0x2d9bfa}}} + }, + { + /* 1*16^49*G: */ + {{{0x1a34d24f, 0x111b196e, 0x084dd007, 0x0db1e193, 0x02ee541b, 0x0fb6f67a, 0x1a764e47, 0x0878b9e2, 0xe4a42d}}, + {{0x1eba9414, 0x13fb898e, 0x16393c4e, 0x0dddbf51, 0x0d34ce88, 0x0ce67dc5, 0x1cd49bf2, 0x1ce2da38, 0x4d9f92}}}, + /* 3*16^49*G: */ + {{{0x1bea0c68, 0x04208579, 0x1ece4ad7, 0x060246ce, 0x16faf094, 0x1e47469c, 0x0e892526, 0x069c2ad4, 0x3e4196}}, + {{0x1a45edb6, 0x05db7fb8, 0x0f3686af, 0x02328c60, 0x093062fa, 0x05ff1b83, 0x07dfcdcf, 0x13b24964, 0x123c5}}}, + /* 5*16^49*G: */ + {{{0x139824d7, 0x1bae91e4, 0x072625eb, 0x0f6c986a, 0x10b576eb, 0x11f317bf, 0x1423bb52, 0x1ea8abae, 0x8d9438}}, + {{0x1366489f, 0x10027a44, 0x1ac18f62, 0x13c57064, 0x0ef6f8fb, 0x05e98d5b, 0x10a8b298, 0x0e69fdcd, 0x3261e0}}}, + /* 7*16^49*G: */ + {{{0x18d713de, 0x124038d4, 0x0a398823, 0x0185f6e8, 0x14543936, 0x089517f2, 0x1108352a, 0x18ab1dca, 0xb72524}}, + {{0x1b8350e9, 0x17ff292c, 0x1297f2dd, 0x05a4dfc8, 0x09415048, 0x08c174eb, 0x1914410b, 0x13514507, 0x4c51b3}}}, + /* 9*16^49*G: */ + {{{0x1e3b2cb4, 0x0636149f, 0x1c84100b, 0x13e6b7e6, 0x1149e304, 0x1b71c090, 0x09466b71, 0x0b442da2, 0x3de45f}}, + {{0x107eb02f, 0x10f19d61, 0x01c1133d, 0x1c51ccb5, 0x09106823, 0x055254be, 0x17714382, 0x13080bd5, 0xba2a85}}}, + /* 11*16^49*G: */ + {{{0x0ce4e5bf, 0x11a3b37b, 0x04016c5c, 0x0f950d41, 0x106ae9b6, 0x1e71ba44, 0x1a1f078f, 0x18d12b37, 0x8511f1}}, + {{0x01789c08, 0x1e494a26, 0x14d9498b, 0x10f11378, 0x000232da, 0x0fbf6355, 0x121d3077, 0x19f2379a, 0xecdff5}}}, + /* 13*16^49*G: */ + {{{0x1d3258ab, 0x0dab3451, 0x0f05370c, 0x04850315, 0x0ab5957d, 0x0e39770a, 0x0088b3e8, 0x05d039ec, 0x8c5a05}}, + {{0x022d0f8f, 0x0bf04298, 0x16512b79, 0x15d1f381, 0x008c246d, 0x0063c826, 0x16841e6a, 0x09768877, 0x6811db}}}, + /* 15*16^49*G: */ + {{{0x1f91bcee, 0x0c615055, 0x03036105, 0x1e3b1e3c, 0x1f137f5c, 0x1e762ab5, 0x1582f718, 0x02dbd7a6, 0xcef7f8}}, + {{0x01966b33, 0x1da6d4fc, 0x1cbdab1a, 0x1c960542, 0x1245fa63, 0x199ce00e, 0x1c04918e, 0x106c6e90, 0x67e74c}}} + }, + { + /* 1*16^50*G: */ + {{{0x0300bf19, 0x18b9dcea, 0x03fa9251, 0x0a6aed51, 0x12b6b92b, 0x07d6d59a, 0x17655058, 0x1de6c197, 0x1ec80f}}, + {{0x0107cefd, 0x18e6e0e6, 0x05681ed9, 0x0dcefec5, 0x1bf5e014, 0x04ac53d5, 0x1034bce9, 0x06ead6a6, 0xaeefe9}}}, + /* 3*16^50*G: */ + {{{0x12fea1f9, 0x18be5de2, 0x0114ae52, 0x1e16a118, 0x06531c4f, 0x0ed5b388, 0x0ba0ef3f, 0x014aba3e, 0xa6dc88}}, + {{0x1bc345e9, 0x18e0a723, 0x1a3df98e, 0x1713b6fc, 0x0bc50057, 0x01d08b56, 0x1f0c0e1a, 0x0a8fb86c, 0x7ef1a8}}}, + /* 5*16^50*G: */ + {{{0x06d6c9b3, 0x06a061f8, 0x01958df2, 0x1899d0e9, 0x081ba8c6, 0x114e3c52, 0x1664af70, 0x07fd4848, 0xfe6ba9}}, + {{0x0948bdfb, 0x0163c47d, 0x10ba6c03, 0x01e37e0b, 0x13b56d98, 0x00d9a2a0, 0x01cadaed, 0x1ae80a73, 0x7ee918}}}, + /* 7*16^50*G: */ + {{{0x0cf95151, 0x11788398, 0x0b12d910, 0x0900dc88, 0x0ded1b96, 0x04616e04, 0x02fec083, 0x1e28df93, 0x15d5e2}}, + {{0x0ff8ecf2, 0x01503e61, 0x16303e52, 0x009f72fb, 0x023f9bb2, 0x1084bc48, 0x13b1fe43, 0x06322bfa, 0xa5b72e}}}, + /* 9*16^50*G: */ + {{{0x096a5658, 0x0bc085c9, 0x1bd9590f, 0x0964a483, 0x029be381, 0x100493d7, 0x11eb631f, 0x0e4ad108, 0x84c0e8}}, + {{0x181b80d1, 0x0cb394de, 0x13c7f48b, 0x0c35303e, 0x1725ed3a, 0x118c8329, 0x0b12821f, 0x10182c04, 0x265983}}}, + /* 11*16^50*G: */ + {{{0x14dc6a0f, 0x1addae44, 0x1f855d4d, 0x06832285, 0x077c2744, 0x1273d160, 0x0c755949, 0x18e3526e, 0xfed6b1}}, + {{0x176fc7e0, 0x05c6b96c, 0x0ff10273, 0x09ab2614, 0x1ae23137, 0x0c0d7269, 0x1c2a11e4, 0x1cd61fff, 0x8de2ab}}}, + /* 13*16^50*G: */ + {{{0x18e29355, 0x19c42f88, 0x1c8361b6, 0x191d2672, 0x1b9d82f1, 0x1c302011, 0x0f1c3f3b, 0x1b325a79, 0x2a6a4d}}, + {{0x15cc2872, 0x029f007d, 0x1131db00, 0x00b474c9, 0x0f90dfe9, 0x0e40f134, 0x1831d83f, 0x174f894f, 0x8677df}}}, + /* 15*16^50*G: */ + {{{0x0148dabf, 0x1cfd447f, 0x075e3ac7, 0x1ba57269, 0x0e735c1a, 0x07611afd, 0x151b65d9, 0x004d924e, 0xe42d93}}, + {{0x011e1361, 0x1b963ab4, 0x19dfae75, 0x04eae033, 0x18530327, 0x0675fef9, 0x12c362ce, 0x058dc5b0, 0x641386}}} + }, + { + /* 1*16^51*G: */ + {{{0x166642be, 0x0edac941, 0x162ea227, 0x0920e2fa, 0x1fa8bce3, 0x057a3406, 0x10be46c0, 0x11808ce1, 0x146a77}}, + {{0x1d83efd0, 0x0594ba41, 0x1f97b474, 0x152e3a5e, 0x0b2870aa, 0x0c13fcea, 0x0a2b759a, 0x1d866a80, 0xb318e0}}}, + /* 3*16^51*G: */ + {{{0x07315443, 0x0c9c39c1, 0x1a19ca67, 0x1377aa95, 0x142a13d7, 0x04cc1050, 0x0d7fd0b2, 0x0080cc12, 0xfc696c}}, + {{0x17d28960, 0x0486b05a, 0x06f46c5d, 0x1fe90c21, 0x077b5487, 0x10e6eb4b, 0x024aefc3, 0x1d7f076b, 0xe0ce27}}}, + /* 5*16^51*G: */ + {{{0x16fdb4eb, 0x0dd97ae0, 0x0b9a9e74, 0x07baf38c, 0x0b0928fa, 0x151ab15f, 0x0ab46b95, 0x043fe9fe, 0x974af2}}, + {{0x09f6f484, 0x004e1efd, 0x1ff08d21, 0x18ae5477, 0x090ed111, 0x121e8160, 0x0f299347, 0x0faa6a00, 0x555238}}}, + /* 7*16^51*G: */ + {{{0x1d5aeee3, 0x1c8256da, 0x163204dc, 0x109786cc, 0x070c5e82, 0x0d9d3349, 0x062c2448, 0x13693bc7, 0x5baab5}}, + {{0x10f69717, 0x1694d7db, 0x14c7bb60, 0x1bb93b57, 0x1daf7215, 0x004330ff, 0x1a15b968, 0x0c2f81ef, 0x8a577f}}}, + /* 9*16^51*G: */ + {{{0x15726890, 0x08d8f227, 0x00df4561, 0x004bfd59, 0x10a0ee59, 0x17e75fc8, 0x10f4040c, 0x14fd6938, 0xfb685f}}, + {{0x1835783a, 0x0375479d, 0x039e6c98, 0x0d9625d2, 0x0ba094fa, 0x10b6cc32, 0x18ba1a72, 0x045931cb, 0xd750df}}}, + /* 11*16^51*G: */ + {{{0x08bca48a, 0x0325f89d, 0x0f7d8bd5, 0x09abe9d0, 0x1f71d78b, 0x1dc8e143, 0x05682ac9, 0x1ecb3c53, 0x5de58f}}, + {{0x12fd41cd, 0x03ca7406, 0x03e2aa56, 0x0b7b389c, 0x13c843fe, 0x111e1296, 0x0d54c269, 0x07b006b3, 0x685a3b}}}, + /* 13*16^51*G: */ + {{{0x05ef63b6, 0x0f1c1a27, 0x06c60baf, 0x09a02ce6, 0x1c1c85ab, 0x1fed1da7, 0x02febc6d, 0x19bd5ac3, 0x6f1825}}, + {{0x05c655f3, 0x1642367a, 0x1fe51504, 0x12b4c804, 0x134553c8, 0x1026bc19, 0x046e63d0, 0x0fbab232, 0xff097e}}}, + /* 15*16^51*G: */ + {{{0x14a63f3b, 0x1a823f6f, 0x1e3e5c9e, 0x00760332, 0x0c765832, 0x08afaf3b, 0x0ddad61c, 0x12beec54, 0xc5ecb8}}, + {{0x05005024, 0x09f9ba34, 0x0c2fb96d, 0x16cbdcbc, 0x033ec8be, 0x002c7fc9, 0x07cdd3a9, 0x03032f10, 0x222525}}} + }, + { + /* 1*16^52*G: */ + {{{0x1180eef9, 0x0bb543c9, 0x0a2e5ddb, 0x00244134, 0x07b128d0, 0x075d8d50, 0x17c1f8eb, 0x1ec3a45c, 0xfa50c0}}, + {{0x1f4f2811, 0x066c6be9, 0x1e884ece, 0x1065274a, 0x1a68a5e6, 0x09439140, 0x0ea6dcb3, 0x124472fd, 0x6b84c6}}}, + /* 3*16^52*G: */ + {{{0x11da5e12, 0x0f70719c, 0x12b2ca5c, 0x0c14802b, 0x0a2b6a9c, 0x14fc9d0e, 0x0c6f368c, 0x07886f3c, 0xf7502e}}, + {{0x0385f4eb, 0x125ce2f4, 0x0973af1e, 0x0da65dee, 0x072047b8, 0x04a2e1eb, 0x0bf5665c, 0x1dbacf9f, 0x3c57f5}}}, + /* 5*16^52*G: */ + {{{0x10b7d105, 0x03a49988, 0x195f27c8, 0x14b89729, 0x055b3f4c, 0x1b31271a, 0x018a8e93, 0x1f3075cb, 0x12fe78}}, + {{0x1f794a60, 0x0c5637dc, 0x1ba42e11, 0x19c4cbad, 0x1cb771de, 0x0d50ccd3, 0x13dde1ad, 0x14671ad7, 0x2062f1}}}, + /* 7*16^52*G: */ + {{{0x1e0c5d05, 0x110ec19c, 0x15cb6bfd, 0x1cd8a154, 0x04b1a480, 0x1d881404, 0x1cf56312, 0x0268fbe8, 0x76aac3}}, + {{0x11ece63e, 0x0b30cdba, 0x179bb8d5, 0x044b9e02, 0x0625f4b1, 0x19641901, 0x03beafbc, 0x1de1ab8e, 0xef5576}}}, + /* 9*16^52*G: */ + {{{0x1c53c086, 0x1137a42f, 0x0686bb27, 0x0ab86939, 0x08104c6b, 0x0618a2f4, 0x13321f98, 0x0b77cb8b, 0xa663fe}}, + {{0x05016201, 0x14e28195, 0x0653f039, 0x1d994ae7, 0x03dc3991, 0x081644c1, 0x1efd746c, 0x0fed6423, 0xb54199}}}, + /* 11*16^52*G: */ + {{{0x0b758574, 0x16c00f6a, 0x13e71ba6, 0x04cd1286, 0x0bdf3d83, 0x10813d71, 0x16096df2, 0x0f4040d9, 0xde9552}}, + {{0x1b67232a, 0x1bef8fe7, 0x168b7ad2, 0x0d420a2a, 0x09ed7bae, 0x0e423f8b, 0x05393887, 0x0ad5927a, 0x4cd3e0}}}, + /* 13*16^52*G: */ + {{{0x1d85474f, 0x1bcdc55f, 0x18d19a35, 0x18945712, 0x05aea894, 0x065f223c, 0x0b76ffb7, 0x1c0cda65, 0x8da6bc}}, + {{0x1d7b4ef7, 0x1efce3e9, 0x16f75e97, 0x198b260b, 0x1fff10b1, 0x0fae838e, 0x13fe13f7, 0x0d5e63da, 0x13fc6c}}}, + /* 15*16^52*G: */ + {{{0x1dd042ea, 0x1aea12b3, 0x03abf41a, 0x144d4c8b, 0x093beebf, 0x1324f19e, 0x08e6c6f5, 0x18f9f677, 0x7329ac}}, + {{0x0f5c94a1, 0x0d467f61, 0x1ead3c2b, 0x112ee63b, 0x168ee184, 0x073ca7d5, 0x1c5224a1, 0x06a836ed, 0x927249}}} + }, + { + /* 1*16^53*G: */ + {{{0x1f067ec2, 0x129e995a, 0x0ee94883, 0x11156bab, 0x0e8421a2, 0x1fb5bec4, 0x0846c696, 0x1a194e43, 0xda1d61}}, + {{0x1ad836f1, 0x0afdd078, 0x1e6d2299, 0x0e7133a4, 0x11e2966a, 0x1b30b0e4, 0x01b1e701, 0x0b4f9326, 0x8157f5}}}, + /* 3*16^53*G: */ + {{{0x1a95a8db, 0x0ec3b997, 0x074dbd85, 0x1d81888f, 0x11723b83, 0x13234c8d, 0x141067a5, 0x148c607b, 0xe3e90d}}, + {{0x1b0d1cf9, 0x00b67bf8, 0x06134f44, 0x03df2f99, 0x0e76afbb, 0x15486381, 0x1e2ec03e, 0x1800ad82, 0xfbe53b}}}, + /* 5*16^53*G: */ + {{{0x112ee214, 0x1d57eb20, 0x04c55005, 0x149d2f2b, 0x0c01c782, 0x086feae0, 0x1dd6a2d9, 0x18e65c7a, 0x9f4ffe}}, + {{0x1085f37a, 0x17a21112, 0x12200a0f, 0x136d2617, 0x1c69d971, 0x13417eba, 0x1cb983a5, 0x1c2631c5, 0x639ce2}}}, + /* 7*16^53*G: */ + {{{0x1f61a0a5, 0x05b40a28, 0x10538fbe, 0x04a7c367, 0x00b2c4b1, 0x10520fa2, 0x0b06c5c6, 0x05a82269, 0x431f62}}, + {{0x18cef899, 0x15bdbff3, 0x1595dc91, 0x1554086a, 0x1aa7241b, 0x1328cb91, 0x0e3db5b7, 0x0ffcf548, 0xa29832}}}, + /* 9*16^53*G: */ + {{{0x07748503, 0x16133eab, 0x04ca39f2, 0x1c1c8ee6, 0x012ac0e6, 0x1779cfc5, 0x1ee1b2d8, 0x1bbd9cf1, 0x993dba}}, + {{0x1eb0cee2, 0x1d39b09b, 0x02b6a926, 0x10f7ed37, 0x1f51a17f, 0x1c23c3d0, 0x1bade17d, 0x1dd0ad3d, 0xa521a9}}}, + /* 11*16^53*G: */ + {{{0x06d23d80, 0x0f5113ad, 0x11d351e3, 0x17a23e4c, 0x162c0e10, 0x018e5c84, 0x1a968ce5, 0x1740d5ab, 0x75f17a}}, + {{0x080dd57e, 0x03542d81, 0x13a96426, 0x1ff7db76, 0x16292372, 0x1e85f8cd, 0x0a031ff1, 0x1fc2ac73, 0xa07a62}}}, + /* 13*16^53*G: */ + {{{0x01ad3413, 0x115cdb6b, 0x09f5a12b, 0x13800806, 0x07b7a8db, 0x0fa42e5c, 0x12829ba5, 0x0bc23b3e, 0x667855}}, + {{0x1ebca672, 0x12408103, 0x17199804, 0x1c5a2a75, 0x1df9ea6c, 0x136c93e5, 0x191a4949, 0x07bc4f1e, 0x510dda}}}, + /* 15*16^53*G: */ + {{{0x06cc8563, 0x00057ad8, 0x18407aab, 0x09beb7ff, 0x03688922, 0x015ec0cb, 0x1d22b6b2, 0x06c59b4e, 0xebdc4a}}, + {{0x0394ccfa, 0x0d8bde75, 0x0813e492, 0x080f2492, 0x14f07bec, 0x11af366e, 0x0d7e6c7b, 0x089d0ada, 0x659a31}}} + }, + { + /* 1*16^54*G: */ + {{{0x0d064e13, 0x139d8308, 0x1bc7818a, 0x023bc088, 0x14166153, 0x1fcc747e, 0x1a41c857, 0x1fe192e0, 0xa8e282}}, + {{0x11f4cc0c, 0x17be3988, 0x175af5b3, 0x0f347ca1, 0x115888b6, 0x1f9e2d92, 0x1026afed, 0x0b71b703, 0x7f9735}}}, + /* 3*16^54*G: */ + {{{0x1a3979b5, 0x150ccd85, 0x1fa0a788, 0x111f1bcc, 0x00e50ba2, 0x1f858f72, 0x098c9fcd, 0x18b9b5bc, 0xae2207}}, + {{0x0450fa6f, 0x079e6b34, 0x153e225a, 0x10f6fa6f, 0x17060fca, 0x092291d6, 0x1dc6b532, 0x0a2180f3, 0xea91fe}}}, + /* 5*16^54*G: */ + {{{0x0efca824, 0x0080c880, 0x08593eb9, 0x1c189fd4, 0x05461e0b, 0x0a08032c, 0x139673b1, 0x0195ae55, 0xcb8ded}}, + {{0x0f227361, 0x0a05e82c, 0x04c5d0bc, 0x1a3fbf8f, 0x0cbc496a, 0x16243d16, 0x03216cc5, 0x11ee81b1, 0x33a500}}}, + /* 7*16^54*G: */ + {{{0x1bcbd327, 0x008da6d1, 0x192abba5, 0x1c10a443, 0x16ed6b04, 0x04806bf3, 0x0d9c23a5, 0x05315e30, 0xb0c53b}}, + {{0x0d7be436, 0x10b5e251, 0x18da83c5, 0x144418e8, 0x0b2afd82, 0x15300db3, 0x1a858e3d, 0x0803f7af, 0xee2a97}}}, + /* 9*16^54*G: */ + {{{0x17b836a1, 0x1377db1c, 0x19e7bdf7, 0x0c80bfee, 0x1f526c80, 0x0317673b, 0x04835362, 0x07e653b7, 0x6f6ba7}}, + {{0x06832b84, 0x0def97d8, 0x187fe4d3, 0x1218a511, 0x0e9c0d89, 0x1c5202df, 0x0638f6c2, 0x02ffebf8, 0xdc778a}}}, + /* 11*16^54*G: */ + {{{0x1eb39ede, 0x1771a104, 0x0184b50a, 0x110065ae, 0x04360310, 0x1a33f081, 0x0bd2ef3f, 0x0fb8e845, 0x7d471a}}, + {{0x0bf6607e, 0x04de6ca5, 0x08aa3f43, 0x0b9efa38, 0x086fa779, 0x1118f7fe, 0x15941ee0, 0x033e74d0, 0x4a7b}}}, + /* 13*16^54*G: */ + {{{0x165eb1c1, 0x0b6a4f12, 0x0b9716a9, 0x1aeacf9b, 0x0f0967fc, 0x1e618cc1, 0x1eb1c1c3, 0x0c7f36e7, 0xf00251}}, + {{0x0dde2ae0, 0x0d3eb823, 0x1344795f, 0x0dfeb9ad, 0x0afed857, 0x1a52ed13, 0x037d319a, 0x1d1107a4, 0x54ea9}}}, + /* 15*16^54*G: */ + {{{0x1ac32c64, 0x079a849e, 0x0b92fe13, 0x0dfc07d9, 0x1715e0e3, 0x074a87a3, 0x0ea83dc1, 0x00003da4, 0xac1214}}, + {{0x1eb1a867, 0x00956dd6, 0x14fc2262, 0x14ba74b4, 0x099a3ed5, 0x1b4ab982, 0x0ebc61c2, 0x19758671, 0xce8ebc}}} + }, + { + /* 1*16^55*G: */ + {{{0x0319497c, 0x179c16f4, 0x09423008, 0x1363f4a2, 0x1cab15d5, 0x12b73489, 0x161cb4e7, 0x17393450, 0x174a53}}, + {{0x079afa73, 0x1ed09d60, 0x0e6150e0, 0x16743b19, 0x1f9e6646, 0x0aaf9623, 0x10595ed0, 0x06f57f93, 0xccc9dc}}}, + /* 3*16^55*G: */ + {{{0x154b8367, 0x0a4039eb, 0x1541affa, 0x0b6efacf, 0x16a5db77, 0x12ea2c21, 0x09b9032a, 0x095c88ca, 0x5e5a09}}, + {{0x11ce85ca, 0x0994d4ec, 0x197fe911, 0x1553de7b, 0x04b7a796, 0x00f8ab95, 0x18170b24, 0x19348f2b, 0xae8af8}}}, + /* 5*16^55*G: */ + {{{0x17b10d9d, 0x0cc2bc9c, 0x07e3f2bc, 0x0a5e313a, 0x0b82de6a, 0x05c19886, 0x1a1677b3, 0x15b72e05, 0xd4e0}}, + {{0x1140dced, 0x01080243, 0x18b648fa, 0x113192f1, 0x087f70b5, 0x1c232191, 0x10251f4b, 0x130306ec, 0x87b801}}}, + /* 7*16^55*G: */ + {{{0x1c9caee8, 0x0408d304, 0x089c2ec8, 0x1c408b63, 0x0a667632, 0x10cd7762, 0x1303dbde, 0x026d1dee, 0x36652}}, + {{0x1772b711, 0x14f6351d, 0x056e9fc2, 0x17531265, 0x0944501c, 0x1e340dd3, 0x1b666527, 0x0565527b, 0x1f18c3}}}, + /* 9*16^55*G: */ + {{{0x1446c85c, 0x1ffcba8c, 0x007018d4, 0x0fbc11cc, 0x0c6eade3, 0x1b6229fb, 0x1c7ea819, 0x00adfb71, 0xe5891}}, + {{0x0148972e, 0x1b63bf39, 0x1376b757, 0x00469d01, 0x01898f49, 0x00c5d7a4, 0x0f683b1d, 0x0be23f4f, 0xe39a48}}}, + /* 11*16^55*G: */ + {{{0x022e1259, 0x18c56f9e, 0x004d8abf, 0x0e73480d, 0x17771931, 0x1afd5003, 0x18fcadb3, 0x0da4de28, 0xa74012}}, + {{0x134a5f43, 0x1bb8b921, 0x075b6b57, 0x0cbcea76, 0x07ee5178, 0x18ba533e, 0x07fc6c17, 0x175e329e, 0x5a9ff}}}, + /* 13*16^55*G: */ + {{{0x0b08f1fe, 0x0450bd1e, 0x0821eff6, 0x1cfdce17, 0x0d177d7c, 0x02bb2ec1, 0x13929950, 0x042db28e, 0x87e4b8}}, + {{0x0ed5e2ec, 0x0fba564d, 0x1e1b675d, 0x1e47b7ac, 0x0c2cc6e2, 0x1fc7517c, 0x033b35f5, 0x180ecc69, 0xf74e3a}}}, + /* 15*16^55*G: */ + {{{0x01c4d15c, 0x14380735, 0x1039d2e6, 0x1d4f7e0f, 0x14a44105, 0x11606092, 0x0696a4b0, 0x08c7fd4f, 0x35ea1b}}, + {{0x1f3fe1ea, 0x049cdd7b, 0x194257b7, 0x06754060, 0x13b185d6, 0x1d2feba6, 0x0b35e223, 0x0ca373da, 0xad2191}}} + }, + { + /* 1*16^56*G: */ + {{{0x1475b7ba, 0x027eff84, 0x0462cf62, 0x13ce61c9, 0x18cdbe03, 0x0bf6fa80, 0x0170f4f9, 0x1303286f, 0x959396}}, + {{0x1524f2fd, 0x0dc55fc3, 0x1c24e17a, 0x0a7ec990, 0x0d6849c6, 0x1c3525ce, 0x07762e80, 0x05111866, 0x2e7e55}}}, + /* 3*16^56*G: */ + {{{0x0fd69985, 0x04e2eec8, 0x17dcaba8, 0x013996db, 0x0cf149f3, 0x1486fde6, 0x1df9e23d, 0x0eb9d6e5, 0xae976}}, + {{0x1409a003, 0x0e475a08, 0x1b86bfe2, 0x133a82f5, 0x054c5d0b, 0x0ff7028d, 0x1453a6e3, 0x0e7edc91, 0x912199}}}, + /* 5*16^56*G: */ + {{{0x19262b90, 0x0e0c9efe, 0x0f30a6a7, 0x078983fc, 0x05d1fb72, 0x0f8bbc01, 0x04bb26d9, 0x054b582c, 0x2b1586}}, + {{0x083d7557, 0x08ccb732, 0x05226926, 0x0692e1f3, 0x149066f5, 0x06a96d43, 0x0fea9e8c, 0x07b54146, 0x2eb005}}}, + /* 7*16^56*G: */ + {{{0x08e7be40, 0x1fcb8a65, 0x0103b964, 0x05912922, 0x0769af2d, 0x0e0b0b72, 0x199dfba5, 0x1da352dd, 0x6af9ea}}, + {{0x0e387e1c, 0x120b7013, 0x1d655a7e, 0x07eccd41, 0x1dc8145e, 0x152141a3, 0x19259c27, 0x022d200c, 0xb3812a}}}, + /* 9*16^56*G: */ + {{{0x1482801e, 0x135b7d07, 0x0f505574, 0x129f178b, 0x0d6f9407, 0x15a1265c, 0x113bacea, 0x1dc08882, 0x596668}}, + {{0x04870c37, 0x03b8a478, 0x14d4d6b5, 0x0d8396c7, 0x1304e8db, 0x1cb043b8, 0x1d7c7b23, 0x150b775d, 0x949aa0}}}, + /* 11*16^56*G: */ + {{{0x032c19fd, 0x064d973e, 0x000a30f9, 0x1571d20b, 0x10b5b4ac, 0x068bd5ab, 0x01d8bf7d, 0x11036a0a, 0xbe84d1}}, + {{0x12f1281f, 0x1b4a529b, 0x14370dd9, 0x0b4feabc, 0x03994795, 0x12fa4184, 0x02513479, 0x19665b8a, 0xeff960}}}, + /* 13*16^56*G: */ + {{{0x16c69482, 0x08dbafea, 0x0be859ef, 0x156a8026, 0x0bc88cbe, 0x193a6579, 0x1b9507d5, 0x062981af, 0x9867a0}}, + {{0x0f792cd7, 0x178308a3, 0x158a2a45, 0x048b9ea2, 0x099639e6, 0x16aad8dd, 0x0d3e71e4, 0x0b476210, 0xd02e61}}}, + /* 15*16^56*G: */ + {{{0x1d557aa1, 0x0511cec8, 0x007f0a5e, 0x1b25fd9a, 0x1d6abdf1, 0x1975004c, 0x0569649f, 0x08a81b10, 0xa866f2}}, + {{0x01430634, 0x0c0ddda6, 0x184692de, 0x16d38cf8, 0x0e13961e, 0x0c7d2ed8, 0x0d135e4f, 0x1ed50045, 0xb58739}}} + }, + { + /* 1*16^57*G: */ + {{{0x1d82b151, 0x1a89a064, 0x07ee8b6e, 0x01487aac, 0x09a8fcca, 0x108a9d88, 0x195b5916, 0x0a15c803, 0xd2a63a}}, + {{0x1cf89405, 0x00a10ba6, 0x013294b5, 0x1eea15e9, 0x08220a70, 0x172c594a, 0x12dd596b, 0x1f6c887f, 0xe82d86}}}, + /* 3*16^57*G: */ + {{{0x0e4b3ba0, 0x02cfb1af, 0x02fc7c5e, 0x157debe3, 0x1245f5c2, 0x0b8798df, 0x0dcefbf8, 0x00a443ff, 0x410811}}, + {{0x17525595, 0x034b0ee0, 0x08191552, 0x0c930acb, 0x18498133, 0x12d70eb5, 0x19a3cb29, 0x0d2edfea, 0xdc37f3}}}, + /* 5*16^57*G: */ + {{{0x13d98ded, 0x114e4dc4, 0x02808611, 0x1e450677, 0x1d65edbd, 0x114c8298, 0x0323233c, 0x02142d98, 0x63a2a2}}, + {{0x00d1cfc2, 0x0c8cbea7, 0x11e1ce94, 0x17ed4013, 0x194461fa, 0x01992a76, 0x1dbf4194, 0x1c5cffd8, 0x882b42}}}, + /* 7*16^57*G: */ + {{{0x18045445, 0x1430d285, 0x07a35fba, 0x1ee6e320, 0x1bef080f, 0x17172eab, 0x1f28f7c4, 0x0ba893ac, 0xc1581}}, + {{0x0054a206, 0x0a7c3eaa, 0x1633a8c8, 0x00a9c86c, 0x1cd28ba3, 0x1e1db331, 0x045742a4, 0x01475d28, 0x2f30d6}}}, + /* 9*16^57*G: */ + {{{0x03857faf, 0x14891ce6, 0x05865c07, 0x1f95bc3d, 0x0ef7f882, 0x1d47a414, 0x0a70355e, 0x0d7135d1, 0xc757eb}}, + {{0x00584ca4, 0x0eced865, 0x06253040, 0x1a621a20, 0x0c61b627, 0x14f9045f, 0x1cd895cd, 0x19f9a47f, 0xf03a59}}}, + /* 11*16^57*G: */ + {{{0x1459225d, 0x1268c27a, 0x02163443, 0x15eefc5b, 0x002a244f, 0x0a04c8ce, 0x0343e057, 0x15d5b5f4, 0xfa8063}}, + {{0x1ece1507, 0x115bf1db, 0x01f1670e, 0x16d86da0, 0x0425c0a2, 0x11104126, 0x01a45837, 0x120af818, 0xba71f}}}, + /* 13*16^57*G: */ + {{{0x16f0d044, 0x13cff4a0, 0x079869e5, 0x153fa921, 0x0e0a5aab, 0x14e7c317, 0x1ea278bd, 0x18b3a04a, 0x658ca3}}, + {{0x17cb872d, 0x0e8f9977, 0x0633a26b, 0x02cec788, 0x1d37655a, 0x0eb1389d, 0x15183c59, 0x06ef5d44, 0xae5cc1}}}, + /* 15*16^57*G: */ + {{{0x1696756d, 0x1ad64ab9, 0x158505ea, 0x15e2c0ac, 0x1305c676, 0x0cc1ae9f, 0x0aeb3930, 0x0955f23e, 0x31c94b}}, + {{0x1e08ae78, 0x1e22f46e, 0x0b441c2a, 0x1dbf95cd, 0x0160683a, 0x05acd57a, 0x0ea6fd2e, 0x096aadd0, 0xf80f88}}} + }, + { + /* 1*16^58*G: */ + {{{0x1617e073, 0x01b7cda2, 0x0e4c5ecd, 0x197b7a70, 0x1dc866ba, 0x1c4b6be7, 0x1ae243b9, 0x0466a8e3, 0x64587e}}, + {{0x1faf6589, 0x014cf2f4, 0x0ebaacd6, 0x12147226, 0x099a185b, 0x0eb223e1, 0x0b8aba5b, 0x1ab7ed20, 0xd99fcd}}}, + /* 3*16^58*G: */ + {{{0x0e103dd6, 0x0fb8a390, 0x0012166b, 0x0c0980f8, 0x0a17ac34, 0x09e7e2c9, 0x0fe0da88, 0x1aab4840, 0xbc477b}}, + {{0x16f7c343, 0x1c8416c6, 0x0ed12b18, 0x126ae58c, 0x0a6395d2, 0x02a9636f, 0x1549b2eb, 0x0485351b, 0xe31e1e}}}, + /* 5*16^58*G: */ + {{{0x144eab31, 0x086e1d86, 0x198d241f, 0x0b5e2809, 0x1f8e80ac, 0x1a11933d, 0x00e00c0e, 0x1fcb4d77, 0x589db4}}, + {{0x11361f6a, 0x00d75f3a, 0x123e36e5, 0x021caa42, 0x190f31f6, 0x0310125e, 0x0a93d81c, 0x0b821154, 0x625544}}}, + /* 7*16^58*G: */ + {{{0x1a0c2c41, 0x1fcb0b94, 0x00cdb19e, 0x063838ac, 0x0db7c428, 0x0c3056b7, 0x1e8baa28, 0x06fa2dc5, 0x1339b3}}, + {{0x09f1bc2b, 0x02f82a5d, 0x1a48e906, 0x044ff0fb, 0x1a3406b1, 0x1207e889, 0x196e9e8c, 0x0c6c58f5, 0x9f9b29}}}, + /* 9*16^58*G: */ + {{{0x18fc47af, 0x18258fc2, 0x10337b0d, 0x1bfd9065, 0x1b568a8d, 0x194da800, 0x1c5f3140, 0x14226c79, 0x7ff3bb}}, + {{0x19ba43a7, 0x1c30b267, 0x02eb0a5f, 0x0a7635a3, 0x1446b17a, 0x048dba39, 0x18a682f2, 0x15d00314, 0x1f6ba7}}}, + /* 11*16^58*G: */ + {{{0x15213775, 0x0c26b004, 0x150aa640, 0x08527647, 0x07f6100b, 0x149caff6, 0x02ed8507, 0x08c79d6c, 0x8ec670}}, + {{0x1841ffff, 0x100879f3, 0x13d47a43, 0x15314179, 0x1ee0e71d, 0x01a0ae76, 0x0f8c1b99, 0x0df41b4b, 0x8f58a6}}}, + /* 13*16^58*G: */ + {{{0x1452abbb, 0x059ffc69, 0x0e570b8f, 0x154e5fc5, 0x1d495ae6, 0x161ff6ca, 0x06ee276e, 0x16883ce0, 0x83de61}}, + {{0x054eb66e, 0x1028bb58, 0x1390a462, 0x18be6d77, 0x01563d79, 0x1b57c627, 0x027e9afe, 0x0694698c, 0x32f0e3}}}, + /* 15*16^58*G: */ + {{{0x159276f1, 0x0b446137, 0x085ec57a, 0x1c4b6525, 0x0d86833a, 0x1ae007be, 0x076c6a2e, 0x1131ea18, 0x3d7663}}, + {{0x059cbcb3, 0x0f2532dc, 0x0c65e180, 0x03304033, 0x0333ef32, 0x171a6d6c, 0x176d825d, 0x0e6f430f, 0xd37669}}} + }, + { + /* 1*16^59*G: */ + {{{0x1d45e458, 0x0c6b6436, 0x1439ff4d, 0x154d9d44, 0x1de042f0, 0x0369f2a4, 0x0216ce95, 0x1c1c9c9b, 0x8481bd}}, + {{0x1779057e, 0x0b258dac, 0x098b955b, 0x14f38856, 0x0b2ca900, 0x0df9ce76, 0x13761289, 0x11974a80, 0x38ee7b}}}, + /* 3*16^59*G: */ + {{{0x152da17d, 0x10507d20, 0x14191ac5, 0x1827b611, 0x00bc811d, 0x13582ff0, 0x117c2253, 0x03c1ea31, 0x3beaed}}, + {{0x0cc768d2, 0x13824c2f, 0x1fb105b3, 0x1bcef71b, 0x0e1b554c, 0x145f5f40, 0x0b37fbd2, 0x1eab5fef, 0xc3b0d7}}}, + /* 5*16^59*G: */ + {{{0x1a4edcc5, 0x1a7d0bed, 0x00c46dc8, 0x1c644284, 0x15997e74, 0x0fe01c93, 0x15861d4b, 0x14197b93, 0x6e73db}}, + {{0x159da0e4, 0x198fbe6e, 0x019e40de, 0x14efb4e0, 0x08693278, 0x0a844441, 0x1122fa91, 0x1f893dd9, 0xee0ac1}}}, + /* 7*16^59*G: */ + {{{0x0a80b979, 0x04e26212, 0x06aecc50, 0x01ebf465, 0x1c310049, 0x0cbf5523, 0x1649d89f, 0x1126fcb6, 0x7706dd}}, + {{0x0126cfde, 0x067a4082, 0x1fbf8c85, 0x141469fa, 0x09c7117f, 0x0ebcc8f5, 0x1c51dde3, 0x104fab76, 0x8a02a9}}}, + /* 9*16^59*G: */ + {{{0x126fe285, 0x06dce25b, 0x0fbc49f7, 0x17585282, 0x1e06aa45, 0x1e3d20fc, 0x03e034bc, 0x18b25378, 0x16d422}}, + {{0x0155b441, 0x1f07ff36, 0x0d93508c, 0x1e18226e, 0x131b1e93, 0x1f34d31a, 0x1906a2ad, 0x1f4a3c44, 0xdf888}}}, + /* 11*16^59*G: */ + {{{0x1acfa513, 0x11885e55, 0x1838ebab, 0x080f3f34, 0x16a9c4e2, 0x1a23a87a, 0x158ea968, 0x08fdd8ed, 0x1fcc0e}}, + {{0x107afc9c, 0x083add20, 0x060e461d, 0x1bdba2c9, 0x1f9b44be, 0x1c3aa19c, 0x11e2d238, 0x14083c6a, 0x165dc1}}}, + /* 13*16^59*G: */ + {{{0x1edc69b2, 0x0d1383e7, 0x1addc5c8, 0x14c11364, 0x0a386a50, 0x01821ae5, 0x0285cc19, 0x0e75ad97, 0xc12b90}}, + {{0x00dd41dd, 0x19574d81, 0x09eca800, 0x1c3b7c7a, 0x14976b8e, 0x16e44fc4, 0x17c765dc, 0x07fca699, 0x3173c4}}}, + /* 15*16^59*G: */ + {{{0x1961fe4d, 0x1b7ac2ef, 0x041c65ea, 0x0910df16, 0x0a73e8a1, 0x14989896, 0x0a3e8fcf, 0x10bb864f, 0xd059bf}}, + {{0x0ae823c2, 0x0c9ad833, 0x16ad932e, 0x111743e9, 0x155b4fd3, 0x1b2ee424, 0x0978ff81, 0x0c18116a, 0x45107a}}} + }, + { + /* 1*16^60*G: */ + {{{0x0caf666b, 0x06b181fb, 0x0c738c2f, 0x19fda789, 0x1f4637ff, 0x0bcd740b, 0x0aa98ada, 0x0af4f020, 0x13464a}}, + {{0x1f6ecc27, 0x1a4ad483, 0x0250b84f, 0x0601503a, 0x0b0ca48f, 0x019a29e6, 0x1603bdf9, 0x12008c28, 0x69be15}}}, + /* 3*16^60*G: */ + {{{0x0eca5f51, 0x10b5904c, 0x1f26bafc, 0x142e3729, 0x1b5cfdde, 0x0b595f82, 0x1a58b1bb, 0x029bb3dc, 0xdde9d5}}, + {{0x10c638f7, 0x16b4d39e, 0x0255c7e6, 0x1dd7d1bd, 0x18f0950f, 0x19a5853f, 0x04476247, 0x02679c50, 0xb84e69}}}, + /* 5*16^60*G: */ + {{{0x199c88e4, 0x1c83582c, 0x0b51bb0b, 0x1aa27c41, 0x04b179ae, 0x00375890, 0x0dcdba7d, 0x02046d32, 0xfd1a62}}, + {{0x195bc8df, 0x0e4648b2, 0x13003ca6, 0x16e3a92b, 0x17782dc6, 0x0034aa4b, 0x082fec4f, 0x0a973918, 0x1ac97b}}}, + /* 7*16^60*G: */ + {{{0x1f8018ce, 0x0a8adada, 0x024b5a2f, 0x1b4ae71b, 0x06dc7cf2, 0x1e727964, 0x1ae7c4ff, 0x063b1852, 0x4ee485}}, + {{0x1e48381f, 0x01ad30d8, 0x1a01804f, 0x0e92e369, 0x1c5e6710, 0x02046863, 0x02d7f1ed, 0x1a90217f, 0xb68f9e}}}, + /* 9*16^60*G: */ + {{{0x11473678, 0x1429748f, 0x10e4bdc0, 0x00af2a12, 0x0c070cba, 0x18a62adc, 0x036ffd78, 0x13869880, 0xfd76cc}}, + {{0x0d144f4f, 0x10b27754, 0x007210df, 0x051ddc28, 0x12cd6606, 0x10539e81, 0x0f6b83fb, 0x086f0e28, 0xf20465}}}, + /* 11*16^60*G: */ + {{{0x0d7a2193, 0x1805b8a4, 0x05d51bb7, 0x123c89e3, 0x0ea212c6, 0x07413a5a, 0x1008679b, 0x14662476, 0x85a2ab}}, + {{0x10cdcf3a, 0x18641ea5, 0x0ec4909f, 0x0db5bf38, 0x0029fe1c, 0x104168e6, 0x145b60b1, 0x0afd6560, 0x9c1298}}}, + /* 13*16^60*G: */ + {{{0x177568b0, 0x0d8182d9, 0x180ec14d, 0x1d1ba033, 0x1650f35a, 0x16b62bc1, 0x19d1102d, 0x1f8e79ff, 0xd25ddb}}, + {{0x1f39929c, 0x0509c936, 0x0f0fc018, 0x04e7103c, 0x1d92b832, 0x17ba66f3, 0x024e2fab, 0x0eb27f09, 0x7a3aff}}}, + /* 15*16^60*G: */ + {{{0x071d7c13, 0x0ff288c5, 0x03fe8e15, 0x156beff4, 0x0c805641, 0x1f4d4bd5, 0x09c957c1, 0x06287d29, 0x458135}}, + {{0x1aff63cf, 0x11c5e2a9, 0x0f65ae65, 0x000caa85, 0x169c9702, 0x0878bbee, 0x0b62d5fd, 0x1d8292f3, 0x9f5858}}} + }, + { + /* 1*16^61*G: */ + {{{0x0d83f366, 0x16d1d069, 0x1ca16232, 0x1399dbc5, 0x1c97a0cd, 0x0185e60e, 0x18ba6bbd, 0x1eb6e27f, 0xbc4a9d}}, + {{0x181f33c1, 0x1ac6b332, 0x151ec5b5, 0x1153f7f4, 0x198caa6e, 0x1bd6fa5b, 0x1018e0e4, 0x194dcf0b, 0xd3a81}}}, + /* 3*16^61*G: */ + {{{0x1712be3c, 0x03517197, 0x051a99ac, 0x0be31db4, 0x01534729, 0x12edd580, 0x0de34f1c, 0x13b26636, 0x39d734}}, + {{0x1c6ff65c, 0x0180cfa0, 0x09059133, 0x1def4bd9, 0x012e8ef5, 0x1aaa6334, 0x0fdfec49, 0x09eadde7, 0x8f929b}}}, + /* 5*16^61*G: */ + {{{0x1f77f22b, 0x15727de6, 0x1e0b80d6, 0x12e47329, 0x1af26c69, 0x06b614ca, 0x17427947, 0x02fefb83, 0xf0cba6}}, + {{0x1909a03c, 0x1e47163a, 0x08255987, 0x0318fd21, 0x0d04004f, 0x1361b28b, 0x1e627bcc, 0x08627f3b, 0x1a25ab}}}, + /* 7*16^61*G: */ + {{{0x06509c12, 0x0566e6a6, 0x147d1d96, 0x17fc46b7, 0x068ed8d6, 0x18746c39, 0x134c8745, 0x173b642a, 0x381d7a}}, + {{0x0eb46102, 0x03215471, 0x19babdd5, 0x1050b0d9, 0x181e7205, 0x122b9d32, 0x16a7ad74, 0x0b6ffb47, 0xa47aab}}}, + /* 9*16^61*G: */ + {{{0x184fe955, 0x0d9da6b1, 0x18ef3923, 0x12ad4b40, 0x08a53f69, 0x1b9f34a6, 0x1f991e4e, 0x0a8cf570, 0xa703f0}}, + {{0x161344bd, 0x135977de, 0x05c9dfe8, 0x1c2c538b, 0x1199b539, 0x1c96b58c, 0x1eb703a9, 0x06b45608, 0xd500f9}}}, + /* 11*16^61*G: */ + {{{0x06eace58, 0x04cb2b60, 0x1cc8474d, 0x1c8ac745, 0x1a03f1b7, 0x1686b829, 0x035d1b1a, 0x18b55aaa, 0x73c6b3}}, + {{0x0af8654e, 0x0b8548b9, 0x0e34a45c, 0x150f1b77, 0x191c6aa6, 0x04c89b36, 0x1dd06ea4, 0x148e6749, 0x3a2fb4}}}, + /* 13*16^61*G: */ + {{{0x00181d5e, 0x059c45f8, 0x16abc815, 0x03675372, 0x0ddb8de7, 0x069d0e07, 0x1ff68740, 0x1cea0da8, 0xc627f3}}, + {{0x169f886d, 0x13c80531, 0x12f8b0e4, 0x0d600a93, 0x1f7d68ef, 0x0b009c50, 0x098ecb5a, 0x1ae3c885, 0xd78f9d}}}, + /* 15*16^61*G: */ + {{{0x17828b16, 0x07146cfd, 0x09211fcd, 0x0f2b1e51, 0x0de53a04, 0x1a053783, 0x08cfe897, 0x17c1dbfa, 0xbb88fa}}, + {{0x0aea5df7, 0x08a39d10, 0x087a5a71, 0x1502e9c7, 0x19163ec4, 0x02cb008a, 0x0374d177, 0x16609ebd, 0xb73676}}} + }, + { + /* 1*16^62*G: */ + {{{0x05324caa, 0x0a55987f, 0x051ca8e5, 0x16cbc615, 0x0a32e694, 0x063a4a29, 0x0f0348f6, 0x0f7f0531, 0x8c28a9}}, + {{0x0bef9482, 0x138ee39e, 0x072e5167, 0x0f09e08a, 0x0c0eb7ae, 0x16f98fbe, 0x064cde3f, 0x0c74660a, 0x40a304}}}, + /* 3*16^62*G: */ + {{{0x0754dd40, 0x11f438aa, 0x0d19b3e1, 0x044c63f8, 0x0f6e9a24, 0x020fe6b9, 0x1f3d16d2, 0x0e06581b, 0x972924}}, + {{0x0aa36143, 0x025a4979, 0x0b2bd24e, 0x15d0a4ab, 0x0df3690d, 0x03aee5ea, 0x08773457, 0x0884cbfd, 0x91d1a2}}}, + /* 5*16^62*G: */ + {{{0x0c2ca7ff, 0x016c175c, 0x17c0868f, 0x06c8bb2b, 0x127af180, 0x08d6ad17, 0x05b8141e, 0x12eb014f, 0x89637f}}, + {{0x10493e68, 0x16a0af0b, 0x10baadef, 0x178d471c, 0x17489f87, 0x0e78aa1a, 0x109355ee, 0x04919110, 0x2d1fe1}}}, + /* 7*16^62*G: */ + {{{0x0ca8dd7f, 0x0c36b1d0, 0x084e0698, 0x0e5006ad, 0x157421bc, 0x0ed01ea9, 0x1824bf72, 0x1ce37c4b, 0x308138}}, + {{0x0a92c7f2, 0x00af923c, 0x12b64579, 0x0cac8c86, 0x08e18c81, 0x1622e8a0, 0x124978e7, 0x1a51051f, 0x28d1e2}}}, + /* 9*16^62*G: */ + {{{0x066a3fb1, 0x06e62b44, 0x04b881b0, 0x00125033, 0x0862f6ec, 0x1a8642db, 0x0d974795, 0x1d054dbd, 0x575fc4}}, + {{0x102655ad, 0x0dc74854, 0x08ebcbc2, 0x076ae78d, 0x087daed3, 0x0de14bc7, 0x128b59c7, 0x120854df, 0x6f6edb}}}, + /* 11*16^62*G: */ + {{{0x190117df, 0x0db54523, 0x08040a48, 0x0a77779c, 0x02a8fda2, 0x137c0f75, 0x0de889fc, 0x06d6c9d5, 0xa5ec90}}, + {{0x186462fe, 0x0094099f, 0x0528d8f6, 0x08c3e0ac, 0x1a0f71c8, 0x1cc1d68f, 0x01003165, 0x0c4bd828, 0xb79dc6}}}, + /* 13*16^62*G: */ + {{{0x172ad712, 0x187cbae0, 0x0411ca42, 0x131961bc, 0x149b95a3, 0x1cbb0a31, 0x0c252779, 0x1d226621, 0xa153df}}, + {{0x0d48fdd2, 0x052fb29c, 0x1c2cca72, 0x0a7e50b5, 0x1b89abd0, 0x0c6af8f8, 0x0cbf120c, 0x0827f60b, 0xfd94d8}}}, + /* 15*16^62*G: */ + {{{0x11cf5b3a, 0x1861b808, 0x0d69e040, 0x0675077b, 0x1c824c44, 0x1a684476, 0x18564d70, 0x18d5ef28, 0x9a541a}}, + {{0x16a44ae4, 0x1faabaf9, 0x07a94b58, 0x11fdc4a4, 0x1475f554, 0x0d79b447, 0x0adf2bf8, 0x1839620d, 0xb66148}}} + }, + { + /* 1*16^63*G: */ + {{{0x1faccae0, 0x0625d088, 0x12eccdd2, 0x166a18b4, 0x11fd23c8, 0x0a672783, 0x1ea30776, 0x0cc272a4, 0x8ea96}}, + {{0x0e62b945, 0x0d79a518, 0x1c3e3a55, 0x0f077d39, 0x1c5d735b, 0x1e067dca, 0x1e0b8939, 0x17791dc4, 0x620efa}}}, + /* 3*16^63*G: */ + {{{0x06a06f5e, 0x0d205acb, 0x0820dc08, 0x0324a2dd, 0x1b716a34, 0x06a10931, 0x14eb0dec, 0x1f7d4284, 0x383b24}}, + {{0x13c6e772, 0x04fa3c36, 0x030ac102, 0x0d5ce977, 0x05a19e8f, 0x0b36aa75, 0x0881133d, 0x0d589db7, 0x54cf70}}}, + /* 5*16^63*G: */ + {{{0x0638a136, 0x1cbae0ea, 0x00e06571, 0x1a39c66d, 0x1790c2b0, 0x0ce35b06, 0x15b5e279, 0x1a07c05d, 0xe68432}}, + {{0x0c6c2584, 0x17e8c084, 0x0d5ccdaa, 0x13c7d7b6, 0x1e6472e0, 0x13981d00, 0x0998934a, 0x02731c6b, 0xca5be4}}}, + /* 7*16^63*G: */ + {{{0x16e8c10c, 0x0743e220, 0x06f5a01f, 0x0530be72, 0x06e7fb47, 0x1ef67398, 0x10a83bbe, 0x0b3c5fcb, 0x395dd5}}, + {{0x05fe638e, 0x01eb6c98, 0x19a48b2f, 0x013809b8, 0x04e274c9, 0x1f43d7fd, 0x0b174104, 0x1a968b25, 0xfd62dc}}}, + /* 9*16^63*G: */ + {{{0x0d6c14ef, 0x0b326d90, 0x1e4f23d4, 0x11f8ea0d, 0x06480085, 0x16adf771, 0x172e7dbb, 0x1b86aa4b, 0x7a514a}}, + {{0x0b3fbd13, 0x169f0c38, 0x09b893de, 0x1d5dee55, 0x15c3729b, 0x185ca647, 0x1363a25f, 0x1fda2a5c, 0x56edd1}}}, + /* 11*16^63*G: */ + {{{0x0f6d65eb, 0x14a31e82, 0x10085492, 0x1220eea8, 0x08f235a9, 0x179dfa48, 0x04363aa3, 0x0b0864bb, 0x1ee1fd}}, + {{0x1d22941c, 0x101b5c92, 0x0d60ac47, 0x05e9d30c, 0x0fcfaca3, 0x1cfe27a1, 0x1cf073ea, 0x1237bad8, 0xbb6928}}}, + /* 13*16^63*G: */ + {{{0x0e36cb44, 0x18ca8778, 0x12880647, 0x1d16d91b, 0x1357d617, 0x07e86c41, 0x0aa2f016, 0x069a71f5, 0x155156}}, + {{0x1f495a68, 0x14d7a328, 0x0830794c, 0x06e2ebe0, 0x1205da8c, 0x11f85a31, 0x08578dc3, 0x18eaaaea, 0xab4fff}}}, + /* 15*16^63*G: */ + {{{0x1427bacc, 0x0fca3083, 0x0b58b854, 0x0662c9ba, 0x1c4aa9e7, 0x07584ac6, 0x0804d8d6, 0x0c88d7ea, 0x3bc6bc}}, + {{0x0ad6fda6, 0x0619feaf, 0x02fad1c5, 0x16eb4a45, 0x0c02bd71, 0x1771136b, 0x0c1736d8, 0x180e2ed8, 0x8e305c}}} + }, diff --git a/applications/external/flipbip/lib/crypto/segwit_addr.c b/applications/external/flipbip/lib/crypto/segwit_addr.c new file mode 100644 index 000000000..1dbc15118 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/segwit_addr.c @@ -0,0 +1,225 @@ +/* Copyright (c) 2017, 2021 Pieter Wuille + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include + +#include "segwit_addr.h" + +static uint32_t bech32_polymod_step(uint32_t pre) { + uint8_t b = pre >> 25; + return ((pre & 0x1FFFFFF) << 5) ^ (-((b >> 0) & 1) & 0x3b6a57b2UL) ^ + (-((b >> 1) & 1) & 0x26508e6dUL) ^ (-((b >> 2) & 1) & 0x1ea119faUL) ^ + (-((b >> 3) & 1) & 0x3d4233ddUL) ^ (-((b >> 4) & 1) & 0x2a1462b3UL); +} + +static uint32_t bech32_final_constant(bech32_encoding enc) { + if(enc == BECH32_ENCODING_BECH32) return 1; + if(enc == BECH32_ENCODING_BECH32M) return 0x2bc830a3; + return 0; +} + +static const char* charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; + +static const int8_t charset_rev[128] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1, -1, 29, + -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, 1, 0, 3, 16, 11, 28, 12, 14, + 6, 4, 2, -1, -1, -1, -1, -1, -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, + 19, -1, 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1}; + +int bech32_encode( + char* output, + const char* hrp, + const uint8_t* data, + size_t data_len, + bech32_encoding enc) { + uint32_t chk = 1; + size_t i = 0; + while(hrp[i] != 0) { + int ch = hrp[i]; + if(ch < 33 || ch > 126) { + return 0; + } + + if(ch >= 'A' && ch <= 'Z') return 0; + chk = bech32_polymod_step(chk) ^ (ch >> 5); + ++i; + } + if(i + 7 + data_len > 90) return 0; + chk = bech32_polymod_step(chk); + while(*hrp != 0) { + chk = bech32_polymod_step(chk) ^ (*hrp & 0x1f); + *(output++) = *(hrp++); + } + *(output++) = '1'; + for(i = 0; i < data_len; ++i) { + if(*data >> 5) return 0; + chk = bech32_polymod_step(chk) ^ (*data); + *(output++) = charset[*(data++)]; + } + for(i = 0; i < 6; ++i) { + chk = bech32_polymod_step(chk); + } + chk ^= bech32_final_constant(enc); + for(i = 0; i < 6; ++i) { + *(output++) = charset[(chk >> ((5 - i) * 5)) & 0x1f]; + } + *output = 0; + return 1; +} + +bech32_encoding bech32_decode(char* hrp, uint8_t* data, size_t* data_len, const char* input) { + uint32_t chk = 1; + size_t i = 0; + size_t input_len = strlen(input); + size_t hrp_len = 0; + int have_lower = 0, have_upper = 0; + if(input_len < 8) { + return BECH32_ENCODING_NONE; + } + *data_len = 0; + while(*data_len < input_len && input[(input_len - 1) - *data_len] != '1') { + ++(*data_len); + } + hrp_len = input_len - (1 + *data_len); + if(1 + *data_len >= input_len || *data_len < 6 || hrp_len > BECH32_MAX_HRP_LEN) { + return BECH32_ENCODING_NONE; + } + *(data_len) -= 6; + for(i = 0; i < hrp_len; ++i) { + int ch = input[i]; + if(ch < 33 || ch > 126) { + return BECH32_ENCODING_NONE; + } + if(ch >= 'a' && ch <= 'z') { + have_lower = 1; + } else if(ch >= 'A' && ch <= 'Z') { + have_upper = 1; + ch = (ch - 'A') + 'a'; + } + hrp[i] = ch; + chk = bech32_polymod_step(chk) ^ (ch >> 5); + } + hrp[i] = 0; + chk = bech32_polymod_step(chk); + for(i = 0; i < hrp_len; ++i) { + chk = bech32_polymod_step(chk) ^ (input[i] & 0x1f); + } + ++i; + while(i < input_len) { + int v = (input[i] & 0x80) ? -1 : charset_rev[(int)input[i]]; + if(input[i] >= 'a' && input[i] <= 'z') have_lower = 1; + if(input[i] >= 'A' && input[i] <= 'Z') have_upper = 1; + if(v == -1) { + return BECH32_ENCODING_NONE; + } + chk = bech32_polymod_step(chk) ^ v; + if(i + 6 < input_len) { + data[i - (1 + hrp_len)] = v; + } + ++i; + } + if(have_lower && have_upper) { + return BECH32_ENCODING_NONE; + } + if(chk == bech32_final_constant(BECH32_ENCODING_BECH32)) { + return BECH32_ENCODING_BECH32; + } else if(chk == bech32_final_constant(BECH32_ENCODING_BECH32M)) { + return BECH32_ENCODING_BECH32M; + } else { + return BECH32_ENCODING_NONE; + } +} + +static int convert_bits( + uint8_t* out, + size_t* outlen, + int outbits, + const uint8_t* in, + size_t inlen, + int inbits, + int pad) { + uint32_t val = 0; + int bits = 0; + uint32_t maxv = (((uint32_t)1) << outbits) - 1; + while(inlen--) { + val = (val << inbits) | *(in++); + bits += inbits; + while(bits >= outbits) { + bits -= outbits; + out[(*outlen)++] = (val >> bits) & maxv; + } + } + if(pad) { + if(bits) { + out[(*outlen)++] = (val << (outbits - bits)) & maxv; + } + } else if(((val << (outbits - bits)) & maxv) || bits >= inbits) { + return 0; + } + return 1; +} + +int segwit_addr_encode( + char* output, + const char* hrp, + int witver, + const uint8_t* witprog, + size_t witprog_len) { + uint8_t data[65] = {0}; + size_t datalen = 0; + bech32_encoding enc = BECH32_ENCODING_BECH32; + if(witver > 16) return 0; + if(witver == 0 && witprog_len != 20 && witprog_len != 32) return 0; + if(witprog_len < 2 || witprog_len > 40) return 0; + if(witver > 0) enc = BECH32_ENCODING_BECH32M; + data[0] = witver; + convert_bits(data + 1, &datalen, 5, witprog, witprog_len, 8, 1); + ++datalen; + return bech32_encode(output, hrp, data, datalen, enc); +} + +int segwit_addr_decode( + int* witver, + uint8_t* witdata, + size_t* witdata_len, + const char* hrp, + const char* addr) { + uint8_t data[84] = {0}; + char hrp_actual[84] = {0}; + size_t data_len = 0; + if(strlen(addr) > 90) return 0; + bech32_encoding enc = bech32_decode(hrp_actual, data, &data_len, addr); + if(enc == BECH32_ENCODING_NONE) return 0; + if(data_len == 0 || data_len > 65) return 0; + if(strncmp(hrp, hrp_actual, 84) != 0) return 0; + if(data[0] > 16) return 0; + if(data[0] == 0 && enc != BECH32_ENCODING_BECH32) return 0; + if(data[0] > 0 && enc != BECH32_ENCODING_BECH32M) return 0; + *witdata_len = 0; + if(!convert_bits(witdata, witdata_len, 8, data + 1, data_len - 1, 5, 0)) return 0; + if(*witdata_len < 2 || *witdata_len > 40) return 0; + if(data[0] == 0 && *witdata_len != 20 && *witdata_len != 32) return 0; + *witver = data[0]; + return 1; +} diff --git a/applications/external/flipbip/lib/crypto/segwit_addr.h b/applications/external/flipbip/lib/crypto/segwit_addr.h new file mode 100644 index 000000000..2251e5c47 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/segwit_addr.h @@ -0,0 +1,97 @@ +/* Copyright (c) 2017, 2021 Pieter Wuille + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef _SEGWIT_ADDR_H_ +#define _SEGWIT_ADDR_H_ 1 + +#include + +// The maximum length of the Bech32 human-readable part according to BIP-173. +#define BECH32_MAX_HRP_LEN 83 + +/** Encode a SegWit address + * + * Out: output: Pointer to a buffer of size 73 + strlen(hrp) that will be + * updated to contain the null-terminated address. + * In: hrp: Pointer to the null-terminated human readable part to use + * (chain/network specific). + * ver: Version of the witness program (between 0 and 16 inclusive). + * prog: Data bytes for the witness program (between 2 and 40 bytes). + * prog_len: Number of data bytes in prog. + * Returns 1 if successful. + */ +int segwit_addr_encode(char* output, const char* hrp, int ver, const uint8_t* prog, size_t prog_len); + +/** Decode a SegWit address + * + * Out: ver: Pointer to an int that will be updated to contain the witness + * program version (between 0 and 16 inclusive). + * prog: Pointer to a buffer of size 40 that will be updated to + * contain the witness program bytes. + * prog_len: Pointer to a size_t that will be updated to contain the length + * of bytes in prog. + * hrp: Pointer to the null-terminated human readable part that is + * expected (chain/network specific). + * addr: Pointer to the null-terminated address. + * Returns 1 if successful. + */ +int segwit_addr_decode(int* ver, uint8_t* prog, size_t* prog_len, const char* hrp, const char* addr); + +/** Supported encodings. */ +typedef enum { + BECH32_ENCODING_NONE, + BECH32_ENCODING_BECH32, + BECH32_ENCODING_BECH32M +} bech32_encoding; + +/** Encode a Bech32 or Bech32m string + * + * Out: output: Pointer to a buffer of size strlen(hrp) + data_len + 8 that + * will be updated to contain the null-terminated Bech32 string. + * In: hrp : Pointer to the null-terminated human readable part. + * data : Pointer to an array of 5-bit values. + * data_len: Length of the data array. + * enc: Which encoding to use (BECH32_ENCODING_BECH32{,M}). + * Returns 1 if successful. + */ +int bech32_encode( + char* output, + const char* hrp, + const uint8_t* data, + size_t data_len, + bech32_encoding enc); + +/** Decode a Bech32 or Bech32m string + * + * Out: hrp: Pointer to a buffer of size BECH32_MAX_HRP_LEN + 1. Will be + * updated to contain the null-terminated human readable part. + * data: Pointer to a buffer of size strlen(input) - 8 that will + * hold the encoded 5-bit data values. + * data_len: Pointer to a size_t that will be updated to be the number + * of entries in data. + * In: input: Pointer to a null-terminated Bech32 string. + * Returns BECH32_ENCODING_BECH32{,M} to indicate decoding was successful + * with the specified encoding standard. BECH32_ENCODING_NONE is returned if + * decoding failed. + */ +bech32_encoding bech32_decode(char* hrp, uint8_t* data, size_t* data_len, const char* input); + +#endif diff --git a/applications/external/flipbip/lib/crypto/setup.py b/applications/external/flipbip/lib/crypto/setup.py new file mode 100644 index 000000000..aee3dd4a9 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/setup.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python +from distutils.core import setup +from distutils.extension import Extension + +from Cython.Build import cythonize +from Cython.Distutils import build_ext + +srcs = [ + "nist256p1", + "base58", + "bignum", + "bip32", + "ecdsa", + "curve25519", + "hmac", + "rand", + "ripemd160", + "secp256k1", + "sha2", +] + +extensions = [ + Extension( + "TrezorCrypto", + sources=["TrezorCrypto.pyx", "c.pxd"] + [x + ".c" for x in srcs], + extra_compile_args=[], + ) +] + +setup( + name="TrezorCrypto", + version="0.0.0", + description="Cython wrapper around trezor-crypto library", + author="Pavol Rusnak", + author_email="stick@satoshilabs.com", + url="https://github.com/trezor/trezor-crypto", + cmdclass={"build_ext": build_ext}, + ext_modules=cythonize(extensions), +) diff --git a/applications/external/flipbip/lib/crypto/sha2.c b/applications/external/flipbip/lib/crypto/sha2.c new file mode 100644 index 000000000..85e589c4d --- /dev/null +++ b/applications/external/flipbip/lib/crypto/sha2.c @@ -0,0 +1,1252 @@ +/** + * Copyright (c) 2000-2001 Aaron D. Gifford + * Copyright (c) 2013-2014 Pavol Rusnak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include "sha2.h" +#include "memzero.h" +#include "byte_order.h" + +/* + * ASSERT NOTE: + * Some sanity checking code is included using assert(). On my FreeBSD + * system, this additional code can be removed by compiling with NDEBUG + * defined. Check your own systems manpage on assert() to see how to + * compile WITHOUT the sanity checking code on your system. + * + * UNROLLED TRANSFORM LOOP NOTE: + * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform + * loop version for the hash transform rounds (defined using macros + * later in this file). Either define on the command line, for example: + * + * cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c + * + * or define below: + * + * #define SHA2_UNROLL_TRANSFORM + * + */ + +/*** SHA-256/384/512 Machine Architecture Definitions *****************/ +/* + * BYTE_ORDER NOTE: + * + * Please make sure that your system defines BYTE_ORDER. If your + * architecture is little-endian, make sure it also defines + * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are + * equivilent. + * + * If your system does not define the above, then you can do so by + * hand like this: + * + * #define LITTLE_ENDIAN 1234 + * #define BIG_ENDIAN 4321 + * + * And for little-endian machines, add: + * + * #define BYTE_ORDER LITTLE_ENDIAN + * + * Or for big-endian machines: + * + * #define BYTE_ORDER BIG_ENDIAN + * + * The FreeBSD machine this was written on defines BYTE_ORDER + * appropriately by including (which in turn includes + * where the appropriate definitions are actually + * made). + */ + +#if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN) +#error Define BYTE_ORDER to be equal to either LITTLE_ENDIAN or BIG_ENDIAN +#endif + +typedef uint8_t sha2_byte; /* Exactly 1 byte */ +typedef uint32_t sha2_word32; /* Exactly 4 bytes */ +typedef uint64_t sha2_word64; /* Exactly 8 bytes */ + +/*** SHA-256/384/512 Various Length Definitions ***********************/ +/* NOTE: Most of these are in sha2.h */ +#define SHA1_SHORT_BLOCK_LENGTH (SHA1_BLOCK_LENGTH - 8) +#define SHA256_SHORT_BLOCK_LENGTH (SHA256_BLOCK_LENGTH - 8) +#define SHA512_SHORT_BLOCK_LENGTH (SHA512_BLOCK_LENGTH - 16) + +/* + * Macro for incrementally adding the unsigned 64-bit integer n to the + * unsigned 128-bit integer (represented using a two-element array of + * 64-bit words): + */ +#define ADDINC128(w, n) \ + { \ + (w)[0] += (sha2_word64)(n); \ + if((w)[0] < (n)) { \ + (w)[1]++; \ + } \ + } + +#define MEMCPY_BCOPY(d, s, l) memcpy((d), (s), (l)) + +/*** THE SIX LOGICAL FUNCTIONS ****************************************/ +/* + * Bit shifting and rotation (used by the six SHA-XYZ logical functions: + * + * NOTE: In the original SHA-256/384/512 document, the shift-right + * function was named R and the rotate-right function was called S. + * (See: http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf on the + * web.) + * + * The newer NIST FIPS 180-2 document uses a much clearer naming + * scheme, SHR for shift-right, ROTR for rotate-right, and ROTL for + * rotate-left. (See: + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf + * on the web.) + * + * WARNING: These macros must be used cautiously, since they reference + * supplied parameters sometimes more than once, and thus could have + * unexpected side-effects if used without taking this into account. + */ + +/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */ +#define SHR(b, x) ((x) >> (b)) +/* 32-bit Rotate-right (used in SHA-256): */ +#define ROTR32(b, x) (((x) >> (b)) | ((x) << (32 - (b)))) +/* 64-bit Rotate-right (used in SHA-384 and SHA-512): */ +#define ROTR64(b, x) (((x) >> (b)) | ((x) << (64 - (b)))) +/* 32-bit Rotate-left (used in SHA-1): */ +#define ROTL32(b, x) (((x) << (b)) | ((x) >> (32 - (b)))) + +/* Two of six logical functions used in SHA-1, SHA-256, SHA-384, and SHA-512: */ +#define Ch(x, y, z) (((x) & (y)) ^ ((~(x)) & (z))) +#define Maj(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) + +/* Function used in SHA-1: */ +#define Parity(x, y, z) ((x) ^ (y) ^ (z)) + +/* Four of six logical functions used in SHA-256: */ +#define Sigma0_256(x) (ROTR32(2, (x)) ^ ROTR32(13, (x)) ^ ROTR32(22, (x))) +#define Sigma1_256(x) (ROTR32(6, (x)) ^ ROTR32(11, (x)) ^ ROTR32(25, (x))) +#define sigma0_256(x) (ROTR32(7, (x)) ^ ROTR32(18, (x)) ^ SHR(3, (x))) +#define sigma1_256(x) (ROTR32(17, (x)) ^ ROTR32(19, (x)) ^ SHR(10, (x))) + +/* Four of six logical functions used in SHA-384 and SHA-512: */ +#define Sigma0_512(x) (ROTR64(28, (x)) ^ ROTR64(34, (x)) ^ ROTR64(39, (x))) +#define Sigma1_512(x) (ROTR64(14, (x)) ^ ROTR64(18, (x)) ^ ROTR64(41, (x))) +#define sigma0_512(x) (ROTR64(1, (x)) ^ ROTR64(8, (x)) ^ SHR(7, (x))) +#define sigma1_512(x) (ROTR64(19, (x)) ^ ROTR64(61, (x)) ^ SHR(6, (x))) + +/*** INTERNAL FUNCTION PROTOTYPES *************************************/ +/* NOTE: These should not be accessed directly from outside this + * library -- they are intended for private internal visibility/use + * only. + */ +static void sha512_Last(SHA512_CTX*); + +/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/ + +/* Hash constant words K for SHA-1: */ +#define K1_0_TO_19 0x5a827999UL +#define K1_20_TO_39 0x6ed9eba1UL +#define K1_40_TO_59 0x8f1bbcdcUL +#define K1_60_TO_79 0xca62c1d6UL + +/* Initial hash value H for SHA-1: */ +const sha2_word32 sha1_initial_hash_value[SHA1_DIGEST_LENGTH / sizeof(sha2_word32)] = + {0x67452301UL, 0xefcdab89UL, 0x98badcfeUL, 0x10325476UL, 0xc3d2e1f0UL}; + +/* Hash constant words K for SHA-256: */ +static const sha2_word32 K256[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, 0x59f111f1UL, + 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, + 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, + 0x0fc19dc6UL, 0x240ca1ccUL, 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, + 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, + 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, + 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, 0xa2bfe8a1UL, 0xa81a664bUL, + 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, + 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, + 0x5b9cca4fUL, 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL}; + +/* Initial hash value H for SHA-256: */ +const sha2_word32 sha256_initial_hash_value[8] = { + 0x6a09e667UL, + 0xbb67ae85UL, + 0x3c6ef372UL, + 0xa54ff53aUL, + 0x510e527fUL, + 0x9b05688cUL, + 0x1f83d9abUL, + 0x5be0cd19UL}; + +/* Hash constant words K for SHA-384 and SHA-512: */ +static const sha2_word64 K512[80] = { + 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, + 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, + 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, + 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, + 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, + 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, + 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, + 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, + 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, + 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, + 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, + 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, + 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, + 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, + 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, + 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, + 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, + 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, + 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL}; + +/* Initial hash value H for SHA-512 */ +const sha2_word64 sha512_initial_hash_value[8] = { + 0x6a09e667f3bcc908ULL, + 0xbb67ae8584caa73bULL, + 0x3c6ef372fe94f82bULL, + 0xa54ff53a5f1d36f1ULL, + 0x510e527fade682d1ULL, + 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, + 0x5be0cd19137e2179ULL}; + +/* + * Constant used by SHA256/384/512_End() functions for converting the + * digest to a readable hexadecimal character string: + */ +static const char* sha2_hex_digits = "0123456789abcdef"; + +/*** SHA-1: ***********************************************************/ +void sha1_Init(SHA1_CTX* context) { + MEMCPY_BCOPY(context->state, sha1_initial_hash_value, SHA1_DIGEST_LENGTH); + memzero(context->buffer, SHA1_BLOCK_LENGTH); + context->bitcount = 0; +} + +#ifdef SHA2_UNROLL_TRANSFORM + +/* Unrolled SHA-1 round macros: */ + +#define ROUND1_0_TO_15(a, b, c, d, e) \ + (e) = ROTL32(5, (a)) + Ch((b), (c), (d)) + (e) + K1_0_TO_19 + (W1[j] = *data++); \ + (b) = ROTL32(30, (b)); \ + j++; + +#define ROUND1_16_TO_19(a, b, c, d, e) \ + T1 = W1[(j + 13) & 0x0f] ^ W1[(j + 8) & 0x0f] ^ W1[(j + 2) & 0x0f] ^ W1[j & 0x0f]; \ + (e) = ROTL32(5, a) + Ch(b, c, d) + e + K1_0_TO_19 + (W1[j & 0x0f] = ROTL32(1, T1)); \ + (b) = ROTL32(30, b); \ + j++; + +#define ROUND1_20_TO_39(a, b, c, d, e) \ + T1 = W1[(j + 13) & 0x0f] ^ W1[(j + 8) & 0x0f] ^ W1[(j + 2) & 0x0f] ^ W1[j & 0x0f]; \ + (e) = ROTL32(5, a) + Parity(b, c, d) + e + K1_20_TO_39 + (W1[j & 0x0f] = ROTL32(1, T1)); \ + (b) = ROTL32(30, b); \ + j++; + +#define ROUND1_40_TO_59(a, b, c, d, e) \ + T1 = W1[(j + 13) & 0x0f] ^ W1[(j + 8) & 0x0f] ^ W1[(j + 2) & 0x0f] ^ W1[j & 0x0f]; \ + (e) = ROTL32(5, a) + Maj(b, c, d) + e + K1_40_TO_59 + (W1[j & 0x0f] = ROTL32(1, T1)); \ + (b) = ROTL32(30, b); \ + j++; + +#define ROUND1_60_TO_79(a, b, c, d, e) \ + T1 = W1[(j + 13) & 0x0f] ^ W1[(j + 8) & 0x0f] ^ W1[(j + 2) & 0x0f] ^ W1[j & 0x0f]; \ + (e) = ROTL32(5, a) + Parity(b, c, d) + e + K1_60_TO_79 + (W1[j & 0x0f] = ROTL32(1, T1)); \ + (b) = ROTL32(30, b); \ + j++; + +void sha1_Transform(const sha2_word32* state_in, const sha2_word32* data, sha2_word32* state_out) { + sha2_word32 a = 0, b = 0, c = 0, d = 0, e = 0; + sha2_word32 T1 = 0; + sha2_word32 W1[16] = {0}; + int j = 0; + + /* Initialize registers with the prev. intermediate value */ + a = state_in[0]; + b = state_in[1]; + c = state_in[2]; + d = state_in[3]; + e = state_in[4]; + + j = 0; + + /* Rounds 0 to 15 unrolled: */ + ROUND1_0_TO_15(a, b, c, d, e); + ROUND1_0_TO_15(e, a, b, c, d); + ROUND1_0_TO_15(d, e, a, b, c); + ROUND1_0_TO_15(c, d, e, a, b); + ROUND1_0_TO_15(b, c, d, e, a); + ROUND1_0_TO_15(a, b, c, d, e); + ROUND1_0_TO_15(e, a, b, c, d); + ROUND1_0_TO_15(d, e, a, b, c); + ROUND1_0_TO_15(c, d, e, a, b); + ROUND1_0_TO_15(b, c, d, e, a); + ROUND1_0_TO_15(a, b, c, d, e); + ROUND1_0_TO_15(e, a, b, c, d); + ROUND1_0_TO_15(d, e, a, b, c); + ROUND1_0_TO_15(c, d, e, a, b); + ROUND1_0_TO_15(b, c, d, e, a); + ROUND1_0_TO_15(a, b, c, d, e); + + /* Rounds 16 to 19 unrolled: */ + ROUND1_16_TO_19(e, a, b, c, d); + ROUND1_16_TO_19(d, e, a, b, c); + ROUND1_16_TO_19(c, d, e, a, b); + ROUND1_16_TO_19(b, c, d, e, a); + + /* Rounds 20 to 39 unrolled: */ + ROUND1_20_TO_39(a, b, c, d, e); + ROUND1_20_TO_39(e, a, b, c, d); + ROUND1_20_TO_39(d, e, a, b, c); + ROUND1_20_TO_39(c, d, e, a, b); + ROUND1_20_TO_39(b, c, d, e, a); + ROUND1_20_TO_39(a, b, c, d, e); + ROUND1_20_TO_39(e, a, b, c, d); + ROUND1_20_TO_39(d, e, a, b, c); + ROUND1_20_TO_39(c, d, e, a, b); + ROUND1_20_TO_39(b, c, d, e, a); + ROUND1_20_TO_39(a, b, c, d, e); + ROUND1_20_TO_39(e, a, b, c, d); + ROUND1_20_TO_39(d, e, a, b, c); + ROUND1_20_TO_39(c, d, e, a, b); + ROUND1_20_TO_39(b, c, d, e, a); + ROUND1_20_TO_39(a, b, c, d, e); + ROUND1_20_TO_39(e, a, b, c, d); + ROUND1_20_TO_39(d, e, a, b, c); + ROUND1_20_TO_39(c, d, e, a, b); + ROUND1_20_TO_39(b, c, d, e, a); + + /* Rounds 40 to 59 unrolled: */ + ROUND1_40_TO_59(a, b, c, d, e); + ROUND1_40_TO_59(e, a, b, c, d); + ROUND1_40_TO_59(d, e, a, b, c); + ROUND1_40_TO_59(c, d, e, a, b); + ROUND1_40_TO_59(b, c, d, e, a); + ROUND1_40_TO_59(a, b, c, d, e); + ROUND1_40_TO_59(e, a, b, c, d); + ROUND1_40_TO_59(d, e, a, b, c); + ROUND1_40_TO_59(c, d, e, a, b); + ROUND1_40_TO_59(b, c, d, e, a); + ROUND1_40_TO_59(a, b, c, d, e); + ROUND1_40_TO_59(e, a, b, c, d); + ROUND1_40_TO_59(d, e, a, b, c); + ROUND1_40_TO_59(c, d, e, a, b); + ROUND1_40_TO_59(b, c, d, e, a); + ROUND1_40_TO_59(a, b, c, d, e); + ROUND1_40_TO_59(e, a, b, c, d); + ROUND1_40_TO_59(d, e, a, b, c); + ROUND1_40_TO_59(c, d, e, a, b); + ROUND1_40_TO_59(b, c, d, e, a); + + /* Rounds 60 to 79 unrolled: */ + ROUND1_60_TO_79(a, b, c, d, e); + ROUND1_60_TO_79(e, a, b, c, d); + ROUND1_60_TO_79(d, e, a, b, c); + ROUND1_60_TO_79(c, d, e, a, b); + ROUND1_60_TO_79(b, c, d, e, a); + ROUND1_60_TO_79(a, b, c, d, e); + ROUND1_60_TO_79(e, a, b, c, d); + ROUND1_60_TO_79(d, e, a, b, c); + ROUND1_60_TO_79(c, d, e, a, b); + ROUND1_60_TO_79(b, c, d, e, a); + ROUND1_60_TO_79(a, b, c, d, e); + ROUND1_60_TO_79(e, a, b, c, d); + ROUND1_60_TO_79(d, e, a, b, c); + ROUND1_60_TO_79(c, d, e, a, b); + ROUND1_60_TO_79(b, c, d, e, a); + ROUND1_60_TO_79(a, b, c, d, e); + ROUND1_60_TO_79(e, a, b, c, d); + ROUND1_60_TO_79(d, e, a, b, c); + ROUND1_60_TO_79(c, d, e, a, b); + ROUND1_60_TO_79(b, c, d, e, a); + + /* Compute the current intermediate hash value */ + state_out[0] = state_in[0] + a; + state_out[1] = state_in[1] + b; + state_out[2] = state_in[2] + c; + state_out[3] = state_in[3] + d; + state_out[4] = state_in[4] + e; + + /* Clean up */ + a = b = c = d = e = T1 = 0; +} + +#else /* SHA2_UNROLL_TRANSFORM */ + +void sha1_Transform(const sha2_word32* state_in, const sha2_word32* data, sha2_word32* state_out) { + sha2_word32 a = 0, b = 0, c = 0, d = 0, e = 0; + sha2_word32 T1 = 0; + sha2_word32 W1[16] = {0}; + int j = 0; + + /* Initialize registers with the prev. intermediate value */ + a = state_in[0]; + b = state_in[1]; + c = state_in[2]; + d = state_in[3]; + e = state_in[4]; + j = 0; + do { + T1 = ROTL32(5, a) + Ch(b, c, d) + e + K1_0_TO_19 + (W1[j] = *data++); + e = d; + d = c; + c = ROTL32(30, b); + b = a; + a = T1; + j++; + } while(j < 16); + + do { + T1 = W1[(j + 13) & 0x0f] ^ W1[(j + 8) & 0x0f] ^ W1[(j + 2) & 0x0f] ^ W1[j & 0x0f]; + T1 = ROTL32(5, a) + Ch(b, c, d) + e + K1_0_TO_19 + (W1[j & 0x0f] = ROTL32(1, T1)); + e = d; + d = c; + c = ROTL32(30, b); + b = a; + a = T1; + j++; + } while(j < 20); + + do { + T1 = W1[(j + 13) & 0x0f] ^ W1[(j + 8) & 0x0f] ^ W1[(j + 2) & 0x0f] ^ W1[j & 0x0f]; + T1 = ROTL32(5, a) + Parity(b, c, d) + e + K1_20_TO_39 + (W1[j & 0x0f] = ROTL32(1, T1)); + e = d; + d = c; + c = ROTL32(30, b); + b = a; + a = T1; + j++; + } while(j < 40); + + do { + T1 = W1[(j + 13) & 0x0f] ^ W1[(j + 8) & 0x0f] ^ W1[(j + 2) & 0x0f] ^ W1[j & 0x0f]; + T1 = ROTL32(5, a) + Maj(b, c, d) + e + K1_40_TO_59 + (W1[j & 0x0f] = ROTL32(1, T1)); + e = d; + d = c; + c = ROTL32(30, b); + b = a; + a = T1; + j++; + } while(j < 60); + + do { + T1 = W1[(j + 13) & 0x0f] ^ W1[(j + 8) & 0x0f] ^ W1[(j + 2) & 0x0f] ^ W1[j & 0x0f]; + T1 = ROTL32(5, a) + Parity(b, c, d) + e + K1_60_TO_79 + (W1[j & 0x0f] = ROTL32(1, T1)); + e = d; + d = c; + c = ROTL32(30, b); + b = a; + a = T1; + j++; + } while(j < 80); + + /* Compute the current intermediate hash value */ + state_out[0] = state_in[0] + a; + state_out[1] = state_in[1] + b; + state_out[2] = state_in[2] + c; + state_out[3] = state_in[3] + d; + state_out[4] = state_in[4] + e; + + /* Clean up */ + a = b = c = d = e = T1 = 0; +} + +#endif /* SHA2_UNROLL_TRANSFORM */ + +void sha1_Update(SHA1_CTX* context, const sha2_byte* data, size_t len) { + unsigned int freespace = 0, usedspace = 0; + + if(len == 0) { + /* Calling with no data is valid - we do nothing */ + return; + } + + usedspace = (context->bitcount >> 3) % SHA1_BLOCK_LENGTH; + if(usedspace > 0) { + /* Calculate how much free space is available in the buffer */ + freespace = SHA1_BLOCK_LENGTH - usedspace; + + if(len >= freespace) { + /* Fill the buffer completely and process it */ + MEMCPY_BCOPY(((uint8_t*)context->buffer) + usedspace, data, freespace); + context->bitcount += freespace << 3; + len -= freespace; + data += freespace; +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for(int j = 0; j < 16; j++) { + REVERSE32(context->buffer[j], context->buffer[j]); + } +#endif + sha1_Transform(context->state, context->buffer, context->state); + } else { + /* The buffer is not yet full */ + MEMCPY_BCOPY(((uint8_t*)context->buffer) + usedspace, data, len); + context->bitcount += len << 3; + /* Clean up: */ + usedspace = freespace = 0; + return; + } + } + while(len >= SHA1_BLOCK_LENGTH) { + /* Process as many complete blocks as we can */ + MEMCPY_BCOPY(context->buffer, data, SHA1_BLOCK_LENGTH); +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for(int j = 0; j < 16; j++) { + REVERSE32(context->buffer[j], context->buffer[j]); + } +#endif + sha1_Transform(context->state, context->buffer, context->state); + context->bitcount += SHA1_BLOCK_LENGTH << 3; + len -= SHA1_BLOCK_LENGTH; + data += SHA1_BLOCK_LENGTH; + } + if(len > 0) { + /* There's left-overs, so save 'em */ + MEMCPY_BCOPY(context->buffer, data, len); + context->bitcount += len << 3; + } + /* Clean up: */ + usedspace = freespace = 0; +} + +void sha1_Final(SHA1_CTX* context, sha2_byte digest[SHA1_DIGEST_LENGTH]) { + unsigned int usedspace = 0; + + /* If no digest buffer is passed, we don't bother doing this: */ + if(digest != (sha2_byte*)0) { + usedspace = (context->bitcount >> 3) % SHA1_BLOCK_LENGTH; + /* Begin padding with a 1 bit: */ + ((uint8_t*)context->buffer)[usedspace++] = 0x80; + + if(usedspace > SHA1_SHORT_BLOCK_LENGTH) { + memzero(((uint8_t*)context->buffer) + usedspace, SHA1_BLOCK_LENGTH - usedspace); + +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for(int j = 0; j < 16; j++) { + REVERSE32(context->buffer[j], context->buffer[j]); + } +#endif + /* Do second-to-last transform: */ + sha1_Transform(context->state, context->buffer, context->state); + + /* And prepare the last transform: */ + usedspace = 0; + } + /* Set-up for the last transform: */ + memzero(((uint8_t*)context->buffer) + usedspace, SHA1_SHORT_BLOCK_LENGTH - usedspace); + +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for(int j = 0; j < 14; j++) { + REVERSE32(context->buffer[j], context->buffer[j]); + } +#endif + /* Set the bit count: */ + context->buffer[14] = context->bitcount >> 32; + context->buffer[15] = context->bitcount & 0xffffffff; + + /* Final transform: */ + sha1_Transform(context->state, context->buffer, context->state); + +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert FROM host byte order */ + for(int j = 0; j < 5; j++) { + REVERSE32(context->state[j], context->state[j]); + } +#endif + MEMCPY_BCOPY(digest, context->state, SHA1_DIGEST_LENGTH); + } + + /* Clean up state data: */ + memzero(context, sizeof(SHA1_CTX)); + usedspace = 0; +} + +char* sha1_End(SHA1_CTX* context, char buffer[SHA1_DIGEST_STRING_LENGTH]) { + sha2_byte digest[SHA1_DIGEST_LENGTH] = {0}, *d = digest; + int i = 0; + + if(buffer != (char*)0) { + sha1_Final(context, digest); + + for(i = 0; i < SHA1_DIGEST_LENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + memzero(context, sizeof(SHA1_CTX)); + } + memzero(digest, SHA1_DIGEST_LENGTH); + return buffer; +} + +void sha1_Raw(const sha2_byte* data, size_t len, uint8_t digest[SHA1_DIGEST_LENGTH]) { + SHA1_CTX context = {0}; + sha1_Init(&context); + sha1_Update(&context, data, len); + sha1_Final(&context, digest); +} + +char* sha1_Data(const sha2_byte* data, size_t len, char digest[SHA1_DIGEST_STRING_LENGTH]) { + SHA1_CTX context = {0}; + + sha1_Init(&context); + sha1_Update(&context, data, len); + return sha1_End(&context, digest); +} + +/*** SHA-256: *********************************************************/ +void sha256_Init(SHA256_CTX* context) { + if(context == (SHA256_CTX*)0) { + return; + } + MEMCPY_BCOPY(context->state, sha256_initial_hash_value, SHA256_DIGEST_LENGTH); + memzero(context->buffer, SHA256_BLOCK_LENGTH); + context->bitcount = 0; +} + +void sha256_Init_ex(SHA256_CTX* context, const uint32_t state[8], uint64_t bitcount) { + if(context == (SHA256_CTX*)0) { + return; + } + MEMCPY_BCOPY(context->state, state, SHA256_DIGEST_LENGTH); + memzero(context->buffer, SHA256_BLOCK_LENGTH); + context->bitcount = bitcount; +} + +#ifdef SHA2_UNROLL_TRANSFORM + +/* Unrolled SHA-256 round macros: */ + +#define ROUND256_0_TO_15(a, b, c, d, e, f, g, h) \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + (W256[j] = *data++); \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + +#define ROUND256(a, b, c, d, e, f, g, h) \ + s0 = W256[(j + 1) & 0x0f]; \ + s0 = sigma0_256(s0); \ + s1 = W256[(j + 14) & 0x0f]; \ + s1 = sigma1_256(s1); \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \ + (W256[j & 0x0f] += s1 + W256[(j + 9) & 0x0f] + s0); \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + +void sha256_Transform(const sha2_word32* state_in, const sha2_word32* data, sha2_word32* state_out) { + sha2_word32 a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0, s0 = 0, s1 = 0; + sha2_word32 T1 = 0; + sha2_word32 W256[16] = {0}; + int j = 0; + + /* Initialize registers with the prev. intermediate value */ + a = state_in[0]; + b = state_in[1]; + c = state_in[2]; + d = state_in[3]; + e = state_in[4]; + f = state_in[5]; + g = state_in[6]; + h = state_in[7]; + + j = 0; + do { + /* Rounds 0 to 15 (unrolled): */ + ROUND256_0_TO_15(a, b, c, d, e, f, g, h); + ROUND256_0_TO_15(h, a, b, c, d, e, f, g); + ROUND256_0_TO_15(g, h, a, b, c, d, e, f); + ROUND256_0_TO_15(f, g, h, a, b, c, d, e); + ROUND256_0_TO_15(e, f, g, h, a, b, c, d); + ROUND256_0_TO_15(d, e, f, g, h, a, b, c); + ROUND256_0_TO_15(c, d, e, f, g, h, a, b); + ROUND256_0_TO_15(b, c, d, e, f, g, h, a); + } while(j < 16); + + /* Now for the remaining rounds to 64: */ + do { + ROUND256(a, b, c, d, e, f, g, h); + ROUND256(h, a, b, c, d, e, f, g); + ROUND256(g, h, a, b, c, d, e, f); + ROUND256(f, g, h, a, b, c, d, e); + ROUND256(e, f, g, h, a, b, c, d); + ROUND256(d, e, f, g, h, a, b, c); + ROUND256(c, d, e, f, g, h, a, b); + ROUND256(b, c, d, e, f, g, h, a); + } while(j < 64); + + /* Compute the current intermediate hash value */ + state_out[0] = state_in[0] + a; + state_out[1] = state_in[1] + b; + state_out[2] = state_in[2] + c; + state_out[3] = state_in[3] + d; + state_out[4] = state_in[4] + e; + state_out[5] = state_in[5] + f; + state_out[6] = state_in[6] + g; + state_out[7] = state_in[7] + h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = 0; +} + +#else /* SHA2_UNROLL_TRANSFORM */ + +void sha256_Transform(const sha2_word32* state_in, const sha2_word32* data, sha2_word32* state_out) { + sha2_word32 a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0, s0 = 0, s1 = 0; + sha2_word32 T1 = 0, T2 = 0, W256[16] = {0}; + int j = 0; + + /* Initialize registers with the prev. intermediate value */ + a = state_in[0]; + b = state_in[1]; + c = state_in[2]; + d = state_in[3]; + e = state_in[4]; + f = state_in[5]; + g = state_in[6]; + h = state_in[7]; + + j = 0; + do { + /* Apply the SHA-256 compression function to update a..h with copy */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++); + T2 = Sigma0_256(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while(j < 16); + + do { + /* Part of the message block expansion: */ + s0 = W256[(j + 1) & 0x0f]; + s0 = sigma0_256(s0); + s1 = W256[(j + 14) & 0x0f]; + s1 = sigma1_256(s1); + + /* Apply the SHA-256 compression function to update a..h */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + + (W256[j & 0x0f] += s1 + W256[(j + 9) & 0x0f] + s0); + T2 = Sigma0_256(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while(j < 64); + + /* Compute the current intermediate hash value */ + state_out[0] = state_in[0] + a; + state_out[1] = state_in[1] + b; + state_out[2] = state_in[2] + c; + state_out[3] = state_in[3] + d; + state_out[4] = state_in[4] + e; + state_out[5] = state_in[5] + f; + state_out[6] = state_in[6] + g; + state_out[7] = state_in[7] + h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = T2 = 0; +} + +#endif /* SHA2_UNROLL_TRANSFORM */ + +void sha256_Update(SHA256_CTX* context, const sha2_byte* data, size_t len) { + unsigned int freespace = 0, usedspace = 0; + + if(len == 0) { + /* Calling with no data is valid - we do nothing */ + return; + } + + usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; + if(usedspace > 0) { + /* Calculate how much free space is available in the buffer */ + freespace = SHA256_BLOCK_LENGTH - usedspace; + + if(len >= freespace) { + /* Fill the buffer completely and process it */ + MEMCPY_BCOPY(((uint8_t*)context->buffer) + usedspace, data, freespace); + context->bitcount += freespace << 3; + len -= freespace; + data += freespace; +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for(int j = 0; j < 16; j++) { + REVERSE32(context->buffer[j], context->buffer[j]); + } +#endif + sha256_Transform(context->state, context->buffer, context->state); + } else { + /* The buffer is not yet full */ + MEMCPY_BCOPY(((uint8_t*)context->buffer) + usedspace, data, len); + context->bitcount += len << 3; + /* Clean up: */ + usedspace = freespace = 0; + return; + } + } + while(len >= SHA256_BLOCK_LENGTH) { + /* Process as many complete blocks as we can */ + MEMCPY_BCOPY(context->buffer, data, SHA256_BLOCK_LENGTH); +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for(int j = 0; j < 16; j++) { + REVERSE32(context->buffer[j], context->buffer[j]); + } +#endif + sha256_Transform(context->state, context->buffer, context->state); + context->bitcount += SHA256_BLOCK_LENGTH << 3; + len -= SHA256_BLOCK_LENGTH; + data += SHA256_BLOCK_LENGTH; + } + if(len > 0) { + /* There's left-overs, so save 'em */ + MEMCPY_BCOPY(context->buffer, data, len); + context->bitcount += len << 3; + } + /* Clean up: */ + usedspace = freespace = 0; +} + +void sha256_Final(SHA256_CTX* context, sha2_byte digest[SHA256_DIGEST_LENGTH]) { + unsigned int usedspace = 0; + + /* If no digest buffer is passed, we don't bother doing this: */ + if(digest != (sha2_byte*)0) { + usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; + /* Begin padding with a 1 bit: */ + ((uint8_t*)context->buffer)[usedspace++] = 0x80; + + if(usedspace > SHA256_SHORT_BLOCK_LENGTH) { + memzero(((uint8_t*)context->buffer) + usedspace, SHA256_BLOCK_LENGTH - usedspace); + +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for(int j = 0; j < 16; j++) { + REVERSE32(context->buffer[j], context->buffer[j]); + } +#endif + /* Do second-to-last transform: */ + sha256_Transform(context->state, context->buffer, context->state); + + /* And prepare the last transform: */ + usedspace = 0; + } + /* Set-up for the last transform: */ + memzero(((uint8_t*)context->buffer) + usedspace, SHA256_SHORT_BLOCK_LENGTH - usedspace); + +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for(int j = 0; j < 14; j++) { + REVERSE32(context->buffer[j], context->buffer[j]); + } +#endif + /* Set the bit count: */ + context->buffer[14] = context->bitcount >> 32; + context->buffer[15] = context->bitcount & 0xffffffff; + + /* Final transform: */ + sha256_Transform(context->state, context->buffer, context->state); + +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert FROM host byte order */ + for(int j = 0; j < 8; j++) { + REVERSE32(context->state[j], context->state[j]); + } +#endif + MEMCPY_BCOPY(digest, context->state, SHA256_DIGEST_LENGTH); + } + + /* Clean up state data: */ + memzero(context, sizeof(SHA256_CTX)); + usedspace = 0; +} + +char* sha256_End(SHA256_CTX* context, char buffer[SHA256_DIGEST_STRING_LENGTH]) { + sha2_byte digest[SHA256_DIGEST_LENGTH] = {0}, *d = digest; + int i = 0; + + if(buffer != (char*)0) { + sha256_Final(context, digest); + + for(i = 0; i < SHA256_DIGEST_LENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + memzero(context, sizeof(SHA256_CTX)); + } + memzero(digest, SHA256_DIGEST_LENGTH); + return buffer; +} + +void sha256_Raw(const sha2_byte* data, size_t len, uint8_t digest[SHA256_DIGEST_LENGTH]) { + SHA256_CTX context = {0}; + sha256_Init(&context); + sha256_Update(&context, data, len); + sha256_Final(&context, digest); +} + +char* sha256_Data(const sha2_byte* data, size_t len, char digest[SHA256_DIGEST_STRING_LENGTH]) { + SHA256_CTX context = {0}; + + sha256_Init(&context); + sha256_Update(&context, data, len); + return sha256_End(&context, digest); +} + +/*** SHA-512: *********************************************************/ +void sha512_Init(SHA512_CTX* context) { + if(context == (SHA512_CTX*)0) { + return; + } + MEMCPY_BCOPY(context->state, sha512_initial_hash_value, SHA512_DIGEST_LENGTH); + memzero(context->buffer, SHA512_BLOCK_LENGTH); + context->bitcount[0] = context->bitcount[1] = 0; +} + +#ifdef SHA2_UNROLL_TRANSFORM + +/* Unrolled SHA-512 round macros: */ +#define ROUND512_0_TO_15(a, b, c, d, e, f, g, h) \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + (W512[j] = *data++); \ + (d) += T1; \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ + j++ + +#define ROUND512(a, b, c, d, e, f, g, h) \ + s0 = W512[(j + 1) & 0x0f]; \ + s0 = sigma0_512(s0); \ + s1 = W512[(j + 14) & 0x0f]; \ + s1 = sigma1_512(s1); \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + \ + (W512[j & 0x0f] += s1 + W512[(j + 9) & 0x0f] + s0); \ + (d) += T1; \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ + j++ + +void sha512_Transform(const sha2_word64* state_in, const sha2_word64* data, sha2_word64* state_out) { + sha2_word64 a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0, s0 = 0, s1 = 0; + sha2_word64 T1 = 0, W512[16] = {0}; + int j = 0; + + /* Initialize registers with the prev. intermediate value */ + a = state_in[0]; + b = state_in[1]; + c = state_in[2]; + d = state_in[3]; + e = state_in[4]; + f = state_in[5]; + g = state_in[6]; + h = state_in[7]; + + j = 0; + do { + ROUND512_0_TO_15(a, b, c, d, e, f, g, h); + ROUND512_0_TO_15(h, a, b, c, d, e, f, g); + ROUND512_0_TO_15(g, h, a, b, c, d, e, f); + ROUND512_0_TO_15(f, g, h, a, b, c, d, e); + ROUND512_0_TO_15(e, f, g, h, a, b, c, d); + ROUND512_0_TO_15(d, e, f, g, h, a, b, c); + ROUND512_0_TO_15(c, d, e, f, g, h, a, b); + ROUND512_0_TO_15(b, c, d, e, f, g, h, a); + } while(j < 16); + + /* Now for the remaining rounds up to 79: */ + do { + ROUND512(a, b, c, d, e, f, g, h); + ROUND512(h, a, b, c, d, e, f, g); + ROUND512(g, h, a, b, c, d, e, f); + ROUND512(f, g, h, a, b, c, d, e); + ROUND512(e, f, g, h, a, b, c, d); + ROUND512(d, e, f, g, h, a, b, c); + ROUND512(c, d, e, f, g, h, a, b); + ROUND512(b, c, d, e, f, g, h, a); + } while(j < 80); + + /* Compute the current intermediate hash value */ + state_out[0] = state_in[0] + a; + state_out[1] = state_in[1] + b; + state_out[2] = state_in[2] + c; + state_out[3] = state_in[3] + d; + state_out[4] = state_in[4] + e; + state_out[5] = state_in[5] + f; + state_out[6] = state_in[6] + g; + state_out[7] = state_in[7] + h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = 0; +} + +#else /* SHA2_UNROLL_TRANSFORM */ + +void sha512_Transform(const sha2_word64* state_in, const sha2_word64* data, sha2_word64* state_out) { + sha2_word64 a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0, s0 = 0, s1 = 0; + sha2_word64 T1 = 0, T2 = 0, W512[16] = {0}; + int j = 0; + + /* Initialize registers with the prev. intermediate value */ + a = state_in[0]; + b = state_in[1]; + c = state_in[2]; + d = state_in[3]; + e = state_in[4]; + f = state_in[5]; + g = state_in[6]; + h = state_in[7]; + + j = 0; + do { + /* Apply the SHA-512 compression function to update a..h with copy */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++); + T2 = Sigma0_512(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while(j < 16); + + do { + /* Part of the message block expansion: */ + s0 = W512[(j + 1) & 0x0f]; + s0 = sigma0_512(s0); + s1 = W512[(j + 14) & 0x0f]; + s1 = sigma1_512(s1); + + /* Apply the SHA-512 compression function to update a..h */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + + (W512[j & 0x0f] += s1 + W512[(j + 9) & 0x0f] + s0); + T2 = Sigma0_512(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while(j < 80); + + /* Compute the current intermediate hash value */ + state_out[0] = state_in[0] + a; + state_out[1] = state_in[1] + b; + state_out[2] = state_in[2] + c; + state_out[3] = state_in[3] + d; + state_out[4] = state_in[4] + e; + state_out[5] = state_in[5] + f; + state_out[6] = state_in[6] + g; + state_out[7] = state_in[7] + h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = T2 = 0; +} + +#endif /* SHA2_UNROLL_TRANSFORM */ + +void sha512_Update(SHA512_CTX* context, const sha2_byte* data, size_t len) { + unsigned int freespace = 0, usedspace = 0; + + if(len == 0) { + /* Calling with no data is valid - we do nothing */ + return; + } + + usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; + if(usedspace > 0) { + /* Calculate how much free space is available in the buffer */ + freespace = SHA512_BLOCK_LENGTH - usedspace; + + if(len >= freespace) { + /* Fill the buffer completely and process it */ + MEMCPY_BCOPY(((uint8_t*)context->buffer) + usedspace, data, freespace); + ADDINC128(context->bitcount, freespace << 3); + len -= freespace; + data += freespace; +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for(int j = 0; j < 16; j++) { + REVERSE64(context->buffer[j], context->buffer[j]); + } +#endif + sha512_Transform(context->state, context->buffer, context->state); + } else { + /* The buffer is not yet full */ + MEMCPY_BCOPY(((uint8_t*)context->buffer) + usedspace, data, len); + ADDINC128(context->bitcount, len << 3); + /* Clean up: */ + usedspace = freespace = 0; + return; + } + } + while(len >= SHA512_BLOCK_LENGTH) { + /* Process as many complete blocks as we can */ + MEMCPY_BCOPY(context->buffer, data, SHA512_BLOCK_LENGTH); +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for(int j = 0; j < 16; j++) { + REVERSE64(context->buffer[j], context->buffer[j]); + } +#endif + sha512_Transform(context->state, context->buffer, context->state); + ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3); + len -= SHA512_BLOCK_LENGTH; + data += SHA512_BLOCK_LENGTH; + } + if(len > 0) { + /* There's left-overs, so save 'em */ + MEMCPY_BCOPY(context->buffer, data, len); + ADDINC128(context->bitcount, len << 3); + } + /* Clean up: */ + usedspace = freespace = 0; +} + +static void sha512_Last(SHA512_CTX* context) { + unsigned int usedspace = 0; + + usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; + /* Begin padding with a 1 bit: */ + ((uint8_t*)context->buffer)[usedspace++] = 0x80; + + if(usedspace > SHA512_SHORT_BLOCK_LENGTH) { + memzero(((uint8_t*)context->buffer) + usedspace, SHA512_BLOCK_LENGTH - usedspace); + +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for(int j = 0; j < 16; j++) { + REVERSE64(context->buffer[j], context->buffer[j]); + } +#endif + /* Do second-to-last transform: */ + sha512_Transform(context->state, context->buffer, context->state); + + /* And prepare the last transform: */ + usedspace = 0; + } + /* Set-up for the last transform: */ + memzero(((uint8_t*)context->buffer) + usedspace, SHA512_SHORT_BLOCK_LENGTH - usedspace); + +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for(int j = 0; j < 14; j++) { + REVERSE64(context->buffer[j], context->buffer[j]); + } +#endif + /* Store the length of input data (in bits): */ + context->buffer[14] = context->bitcount[1]; + context->buffer[15] = context->bitcount[0]; + + /* Final transform: */ + sha512_Transform(context->state, context->buffer, context->state); +} + +void sha512_Final(SHA512_CTX* context, sha2_byte digest[SHA512_DIGEST_LENGTH]) { + /* If no digest buffer is passed, we don't bother doing this: */ + if(digest != (sha2_byte*)0) { + sha512_Last(context); + + /* Save the hash data for output: */ +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert FROM host byte order */ + for(int j = 0; j < 8; j++) { + REVERSE64(context->state[j], context->state[j]); + } +#endif + MEMCPY_BCOPY(digest, context->state, SHA512_DIGEST_LENGTH); + } + + /* Zero out state data */ + memzero(context, sizeof(SHA512_CTX)); +} + +char* sha512_End(SHA512_CTX* context, char buffer[SHA512_DIGEST_STRING_LENGTH]) { + sha2_byte digest[SHA512_DIGEST_LENGTH] = {0}, *d = digest; + int i = 0; + + if(buffer != (char*)0) { + sha512_Final(context, digest); + + for(i = 0; i < SHA512_DIGEST_LENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + memzero(context, sizeof(SHA512_CTX)); + } + memzero(digest, SHA512_DIGEST_LENGTH); + return buffer; +} + +void sha512_Raw(const sha2_byte* data, size_t len, uint8_t digest[SHA512_DIGEST_LENGTH]) { + SHA512_CTX context = {0}; + sha512_Init(&context); + sha512_Update(&context, data, len); + sha512_Final(&context, digest); +} + +char* sha512_Data(const sha2_byte* data, size_t len, char digest[SHA512_DIGEST_STRING_LENGTH]) { + SHA512_CTX context = {0}; + + sha512_Init(&context); + sha512_Update(&context, data, len); + return sha512_End(&context, digest); +} diff --git a/applications/external/flipbip/lib/crypto/sha2.h b/applications/external/flipbip/lib/crypto/sha2.h new file mode 100644 index 000000000..5f7c1f071 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/sha2.h @@ -0,0 +1,92 @@ +/** + * Copyright (c) 2000-2001 Aaron D. Gifford + * Copyright (c) 2013-2014 Pavol Rusnak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef __SHA2_H__ +#define __SHA2_H__ + +#include +#include +#include "byte_order.h" + +#define SHA1_BLOCK_LENGTH 64 +#define SHA1_DIGEST_LENGTH 20 +#define SHA1_DIGEST_STRING_LENGTH (SHA1_DIGEST_LENGTH * 2 + 1) +#define SHA256_BLOCK_LENGTH 64 +#define SHA256_DIGEST_LENGTH 32 +#define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1) +#define SHA512_BLOCK_LENGTH 128 +#define SHA512_DIGEST_LENGTH 64 +#define SHA512_DIGEST_STRING_LENGTH (SHA512_DIGEST_LENGTH * 2 + 1) + +typedef struct _SHA1_CTX { + uint32_t state[5]; + uint64_t bitcount; + uint32_t buffer[SHA1_BLOCK_LENGTH / sizeof(uint32_t)]; +} SHA1_CTX; +typedef struct _SHA256_CTX { + uint32_t state[8]; + uint64_t bitcount; + uint32_t buffer[SHA256_BLOCK_LENGTH / sizeof(uint32_t)]; +} SHA256_CTX; +typedef struct _SHA512_CTX { + uint64_t state[8]; + uint64_t bitcount[2]; + uint64_t buffer[SHA512_BLOCK_LENGTH / sizeof(uint64_t)]; +} SHA512_CTX; + +extern const uint32_t sha256_initial_hash_value[8]; +extern const uint64_t sha512_initial_hash_value[8]; + +void sha1_Transform(const uint32_t* state_in, const uint32_t* data, uint32_t* state_out); +void sha1_Init(SHA1_CTX*); +void sha1_Update(SHA1_CTX*, const uint8_t*, size_t); +void sha1_Final(SHA1_CTX*, uint8_t[SHA1_DIGEST_LENGTH]); +char* sha1_End(SHA1_CTX*, char[SHA1_DIGEST_STRING_LENGTH]); +void sha1_Raw(const uint8_t*, size_t, uint8_t[SHA1_DIGEST_LENGTH]); +char* sha1_Data(const uint8_t*, size_t, char[SHA1_DIGEST_STRING_LENGTH]); + +void sha256_Transform(const uint32_t* state_in, const uint32_t* data, uint32_t* state_out); +void sha256_Init(SHA256_CTX*); +void sha256_Init_ex(SHA256_CTX*, const uint32_t state[8], uint64_t bitcount); +void sha256_Update(SHA256_CTX*, const uint8_t*, size_t); +void sha256_Final(SHA256_CTX*, uint8_t[SHA256_DIGEST_LENGTH]); +char* sha256_End(SHA256_CTX*, char[SHA256_DIGEST_STRING_LENGTH]); +void sha256_Raw(const uint8_t*, size_t, uint8_t[SHA256_DIGEST_LENGTH]); +char* sha256_Data(const uint8_t*, size_t, char[SHA256_DIGEST_STRING_LENGTH]); + +void sha512_Transform(const uint64_t* state_in, const uint64_t* data, uint64_t* state_out); +void sha512_Init(SHA512_CTX*); +void sha512_Update(SHA512_CTX*, const uint8_t*, size_t); +void sha512_Final(SHA512_CTX*, uint8_t[SHA512_DIGEST_LENGTH]); +char* sha512_End(SHA512_CTX*, char[SHA512_DIGEST_STRING_LENGTH]); +void sha512_Raw(const uint8_t*, size_t, uint8_t[SHA512_DIGEST_LENGTH]); +char* sha512_Data(const uint8_t*, size_t, char[SHA512_DIGEST_STRING_LENGTH]); + +#endif diff --git a/applications/external/flipbip/lib/crypto/sha3.c b/applications/external/flipbip/lib/crypto/sha3.c new file mode 100644 index 000000000..d3a43b6a3 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/sha3.c @@ -0,0 +1,392 @@ +/* sha3.c - an implementation of Secure Hash Algorithm 3 (Keccak). + * based on the + * The Keccak SHA-3 submission. Submission to NIST (Round 3), 2011 + * by Guido Bertoni, Joan Daemen, Michaël Peeters and Gilles Van Assche + * + * Copyright: 2013 Aleksey Kravchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk! + */ + +#include +#include + +#include "sha3.h" +#include "memzero.h" +#include "byte_order.h" + +#define I64(x) x##LL +#define ROTL64(qword, n) ((qword) << (n) ^ ((qword) >> (64 - (n)))) +#define le2me_64(x) (x) +#define IS_ALIGNED_64(p) (0 == (((uintptr_t)(const void*)(p)&0x7))) +#define me64_to_le_str(to, from, length) memcpy((to), (from), (length)) + +/* constants */ +#define NumberOfRounds 24 + +/* SHA3 (Keccak) constants for 24 rounds */ +static uint64_t keccak_round_constants[NumberOfRounds] = { + I64(0x0000000000000001), I64(0x0000000000008082), I64(0x800000000000808A), + I64(0x8000000080008000), I64(0x000000000000808B), I64(0x0000000080000001), + I64(0x8000000080008081), I64(0x8000000000008009), I64(0x000000000000008A), + I64(0x0000000000000088), I64(0x0000000080008009), I64(0x000000008000000A), + I64(0x000000008000808B), I64(0x800000000000008B), I64(0x8000000000008089), + I64(0x8000000000008003), I64(0x8000000000008002), I64(0x8000000000000080), + I64(0x000000000000800A), I64(0x800000008000000A), I64(0x8000000080008081), + I64(0x8000000000008080), I64(0x0000000080000001), I64(0x8000000080008008)}; + +/* Initializing a sha3 context for given number of output bits */ +static void keccak_Init(SHA3_CTX* ctx, unsigned bits) { + /* NB: The Keccak capacity parameter = bits * 2 */ + unsigned rate = 1600 - bits * 2; + + memzero(ctx, sizeof(SHA3_CTX)); + ctx->block_size = rate / 8; + assert(rate <= 1600 && (rate % 64) == 0); +} + +/** + * Initialize context before calculating hash. + * + * @param ctx context to initialize + */ +void sha3_224_Init(SHA3_CTX* ctx) { + keccak_Init(ctx, 224); +} + +/** + * Initialize context before calculating hash. + * + * @param ctx context to initialize + */ +void sha3_256_Init(SHA3_CTX* ctx) { + keccak_Init(ctx, 256); +} + +/** + * Initialize context before calculating hash. + * + * @param ctx context to initialize + */ +void sha3_384_Init(SHA3_CTX* ctx) { + keccak_Init(ctx, 384); +} + +/** + * Initialize context before calculating hash. + * + * @param ctx context to initialize + */ +void sha3_512_Init(SHA3_CTX* ctx) { + keccak_Init(ctx, 512); +} + +/* Keccak theta() transformation */ +static void keccak_theta(uint64_t* A) { + unsigned int x = 0; + uint64_t C[5] = {0}, D[5] = {0}; + + for(x = 0; x < 5; x++) { + C[x] = A[x] ^ A[x + 5] ^ A[x + 10] ^ A[x + 15] ^ A[x + 20]; + } + D[0] = ROTL64(C[1], 1) ^ C[4]; + D[1] = ROTL64(C[2], 1) ^ C[0]; + D[2] = ROTL64(C[3], 1) ^ C[1]; + D[3] = ROTL64(C[4], 1) ^ C[2]; + D[4] = ROTL64(C[0], 1) ^ C[3]; + + for(x = 0; x < 5; x++) { + A[x] ^= D[x]; + A[x + 5] ^= D[x]; + A[x + 10] ^= D[x]; + A[x + 15] ^= D[x]; + A[x + 20] ^= D[x]; + } +} + +/* Keccak pi() transformation */ +static void keccak_pi(uint64_t* A) { + uint64_t A1 = 0; + A1 = A[1]; + A[1] = A[6]; + A[6] = A[9]; + A[9] = A[22]; + A[22] = A[14]; + A[14] = A[20]; + A[20] = A[2]; + A[2] = A[12]; + A[12] = A[13]; + A[13] = A[19]; + A[19] = A[23]; + A[23] = A[15]; + A[15] = A[4]; + A[4] = A[24]; + A[24] = A[21]; + A[21] = A[8]; + A[8] = A[16]; + A[16] = A[5]; + A[5] = A[3]; + A[3] = A[18]; + A[18] = A[17]; + A[17] = A[11]; + A[11] = A[7]; + A[7] = A[10]; + A[10] = A1; + /* note: A[ 0] is left as is */ +} + +/* Keccak chi() transformation */ +static void keccak_chi(uint64_t* A) { + int i = 0; + for(i = 0; i < 25; i += 5) { + uint64_t A0 = A[0 + i], A1 = A[1 + i]; + A[0 + i] ^= ~A1 & A[2 + i]; + A[1 + i] ^= ~A[2 + i] & A[3 + i]; + A[2 + i] ^= ~A[3 + i] & A[4 + i]; + A[3 + i] ^= ~A[4 + i] & A0; + A[4 + i] ^= ~A0 & A1; + } +} + +static void sha3_permutation(uint64_t* state) { +#if BYTE_ORDER == BIG_ENDIAN + int i; + for(i = 0; i < 25; i++) { + REVERSE64(state[i], state[i]); + } +#endif + int round = 0; + for(round = 0; round < NumberOfRounds; round++) { + keccak_theta(state); + + /* apply Keccak rho() transformation */ + state[1] = ROTL64(state[1], 1); + state[2] = ROTL64(state[2], 62); + state[3] = ROTL64(state[3], 28); + state[4] = ROTL64(state[4], 27); + state[5] = ROTL64(state[5], 36); + state[6] = ROTL64(state[6], 44); + state[7] = ROTL64(state[7], 6); + state[8] = ROTL64(state[8], 55); + state[9] = ROTL64(state[9], 20); + state[10] = ROTL64(state[10], 3); + state[11] = ROTL64(state[11], 10); + state[12] = ROTL64(state[12], 43); + state[13] = ROTL64(state[13], 25); + state[14] = ROTL64(state[14], 39); + state[15] = ROTL64(state[15], 41); + state[16] = ROTL64(state[16], 45); + state[17] = ROTL64(state[17], 15); + state[18] = ROTL64(state[18], 21); + state[19] = ROTL64(state[19], 8); + state[20] = ROTL64(state[20], 18); + state[21] = ROTL64(state[21], 2); + state[22] = ROTL64(state[22], 61); + state[23] = ROTL64(state[23], 56); + state[24] = ROTL64(state[24], 14); + + keccak_pi(state); + keccak_chi(state); + + /* apply iota(state, round) */ + *state ^= keccak_round_constants[round]; + } +#if BYTE_ORDER == BIG_ENDIAN + for(i = 0; i < 25; i++) { + REVERSE64(state[i], state[i]); + } +#endif +} + +/** + * The core transformation. Process the specified block of data. + * + * @param hash the algorithm state + * @param block the message block to process + * @param block_size the size of the processed block in bytes + */ +static void sha3_process_block(uint64_t hash[25], const uint64_t* block, size_t block_size) { + /* expanded loop */ + hash[0] ^= le2me_64(block[0]); + hash[1] ^= le2me_64(block[1]); + hash[2] ^= le2me_64(block[2]); + hash[3] ^= le2me_64(block[3]); + hash[4] ^= le2me_64(block[4]); + hash[5] ^= le2me_64(block[5]); + hash[6] ^= le2me_64(block[6]); + hash[7] ^= le2me_64(block[7]); + hash[8] ^= le2me_64(block[8]); + /* if not sha3-512 */ + if(block_size > 72) { + hash[9] ^= le2me_64(block[9]); + hash[10] ^= le2me_64(block[10]); + hash[11] ^= le2me_64(block[11]); + hash[12] ^= le2me_64(block[12]); + /* if not sha3-384 */ + if(block_size > 104) { + hash[13] ^= le2me_64(block[13]); + hash[14] ^= le2me_64(block[14]); + hash[15] ^= le2me_64(block[15]); + hash[16] ^= le2me_64(block[16]); + /* if not sha3-256 */ + if(block_size > 136) { + hash[17] ^= le2me_64(block[17]); +#ifdef FULL_SHA3_FAMILY_SUPPORT + /* if not sha3-224 */ + if(block_size > 144) { + hash[18] ^= le2me_64(block[18]); + hash[19] ^= le2me_64(block[19]); + hash[20] ^= le2me_64(block[20]); + hash[21] ^= le2me_64(block[21]); + hash[22] ^= le2me_64(block[22]); + hash[23] ^= le2me_64(block[23]); + hash[24] ^= le2me_64(block[24]); + } +#endif + } + } + } + /* make a permutation of the hash */ + sha3_permutation(hash); +} + +#define SHA3_FINALIZED 0x80000000 + +/** + * Calculate message hash. + * Can be called repeatedly with chunks of the message to be hashed. + * + * @param ctx the algorithm context containing current hashing state + * @param msg message chunk + * @param size length of the message chunk + */ +void sha3_Update(SHA3_CTX* ctx, const unsigned char* msg, size_t size) { + if(size == 0) return; + + size_t idx = (size_t)ctx->rest; + size_t block_size = (size_t)ctx->block_size; + + if(ctx->rest & SHA3_FINALIZED) return; /* too late for additional input */ + ctx->rest = (unsigned)((ctx->rest + size) % block_size); + + /* fill partial block */ + if(idx) { + size_t left = block_size - idx; + memcpy((char*)ctx->message + idx, msg, (size < left ? size : left)); + if(size < left) return; + + /* process partial block */ + sha3_process_block(ctx->hash, ctx->message, block_size); + msg += left; + size -= left; + } + while(size >= block_size) { + uint64_t* aligned_message_block = NULL; + if(IS_ALIGNED_64(msg)) { + /* the most common case is processing of an already aligned message + without copying it */ + aligned_message_block = (uint64_t*)(void*)msg; + } else { + memcpy(ctx->message, msg, block_size); + aligned_message_block = ctx->message; + } + + sha3_process_block(ctx->hash, aligned_message_block, block_size); + msg += block_size; + size -= block_size; + } + if(size) { + memcpy(ctx->message, msg, size); /* save leftovers */ + } +} + +/** + * Store calculated hash into the given array. + * + * @param ctx the algorithm context containing current hashing state + * @param result calculated hash in binary form + */ +void sha3_Final(SHA3_CTX* ctx, unsigned char* result) { + size_t digest_length = 100 - ctx->block_size / 2; + const size_t block_size = ctx->block_size; + + if(!(ctx->rest & SHA3_FINALIZED)) { + /* clear the rest of the data queue */ + memzero((char*)ctx->message + ctx->rest, block_size - ctx->rest); + ((char*)ctx->message)[ctx->rest] |= 0x06; + ((char*)ctx->message)[block_size - 1] |= 0x80; + + /* process final block */ + sha3_process_block(ctx->hash, ctx->message, block_size); + ctx->rest = SHA3_FINALIZED; /* mark context as finalized */ + } + + assert(block_size > digest_length); + if(result) me64_to_le_str(result, ctx->hash, digest_length); + memzero(ctx, sizeof(SHA3_CTX)); +} + +#if USE_KECCAK +/** +* Store calculated hash into the given array. +* +* @param ctx the algorithm context containing current hashing state +* @param result calculated hash in binary form +*/ +void keccak_Final(SHA3_CTX* ctx, unsigned char* result) { + size_t digest_length = 100 - ctx->block_size / 2; + const size_t block_size = ctx->block_size; + + if(!(ctx->rest & SHA3_FINALIZED)) { + /* clear the rest of the data queue */ + memzero((char*)ctx->message + ctx->rest, block_size - ctx->rest); + ((char*)ctx->message)[ctx->rest] |= 0x01; + ((char*)ctx->message)[block_size - 1] |= 0x80; + + /* process final block */ + sha3_process_block(ctx->hash, ctx->message, block_size); + ctx->rest = SHA3_FINALIZED; /* mark context as finalized */ + } + + assert(block_size > digest_length); + if(result) me64_to_le_str(result, ctx->hash, digest_length); + memzero(ctx, sizeof(SHA3_CTX)); +} + +void keccak_256(const unsigned char* data, size_t len, unsigned char* digest) { + SHA3_CTX ctx = {0}; + keccak_256_Init(&ctx); + keccak_Update(&ctx, data, len); + keccak_Final(&ctx, digest); +} + +void keccak_512(const unsigned char* data, size_t len, unsigned char* digest) { + SHA3_CTX ctx = {0}; + keccak_512_Init(&ctx); + keccak_Update(&ctx, data, len); + keccak_Final(&ctx, digest); +} +#endif /* USE_KECCAK */ + +void sha3_256(const unsigned char* data, size_t len, unsigned char* digest) { + SHA3_CTX ctx = {0}; + sha3_256_Init(&ctx); + sha3_Update(&ctx, data, len); + sha3_Final(&ctx, digest); +} + +void sha3_512(const unsigned char* data, size_t len, unsigned char* digest) { + SHA3_CTX ctx = {0}; + sha3_512_Init(&ctx); + sha3_Update(&ctx, data, len); + sha3_Final(&ctx, digest); +} diff --git a/applications/external/flipbip/lib/crypto/sha3.h b/applications/external/flipbip/lib/crypto/sha3.h new file mode 100644 index 000000000..01818a4fe --- /dev/null +++ b/applications/external/flipbip/lib/crypto/sha3.h @@ -0,0 +1,88 @@ +/* sha3.h - an implementation of Secure Hash Algorithm 3 (Keccak). + * based on the + * The Keccak SHA-3 submission. Submission to NIST (Round 3), 2011 + * by Guido Bertoni, Joan Daemen, Michaël Peeters and Gilles Van Assche + * + * Copyright: 2013 Aleksey Kravchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk! + */ + +#ifndef __SHA3_H__ +#define __SHA3_H__ + +#include +#include "options.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define sha3_224_hash_size 28 +#define sha3_256_hash_size 32 +#define sha3_384_hash_size 48 +#define sha3_512_hash_size 64 +#define sha3_max_permutation_size 25 +#define sha3_max_rate_in_qwords 24 + +#define SHA3_224_BLOCK_LENGTH 144 +#define SHA3_256_BLOCK_LENGTH 136 +#define SHA3_384_BLOCK_LENGTH 104 +#define SHA3_512_BLOCK_LENGTH 72 + +#define SHA3_224_DIGEST_LENGTH sha3_224_hash_size +#define SHA3_256_DIGEST_LENGTH sha3_256_hash_size +#define SHA3_384_DIGEST_LENGTH sha3_384_hash_size +#define SHA3_512_DIGEST_LENGTH sha3_512_hash_size + +/** + * SHA3 Algorithm context. + */ +typedef struct SHA3_CTX { + /* 1600 bits algorithm hashing state */ + uint64_t hash[sha3_max_permutation_size]; + /* 1536-bit buffer for leftovers */ + uint64_t message[sha3_max_rate_in_qwords]; + /* count of bytes in the message[] buffer */ + unsigned rest; + /* size of a message block processed at once */ + unsigned block_size; +} SHA3_CTX; + +/* methods for calculating the hash function */ + +void sha3_224_Init(SHA3_CTX* ctx); +void sha3_256_Init(SHA3_CTX* ctx); +void sha3_384_Init(SHA3_CTX* ctx); +void sha3_512_Init(SHA3_CTX* ctx); +void sha3_Update(SHA3_CTX* ctx, const unsigned char* msg, size_t size); +void sha3_Final(SHA3_CTX* ctx, unsigned char* result); + +#if USE_KECCAK +#define keccak_224_Init sha3_224_Init +#define keccak_256_Init sha3_256_Init +#define keccak_384_Init sha3_384_Init +#define keccak_512_Init sha3_512_Init +#define keccak_Update sha3_Update +void keccak_Final(SHA3_CTX* ctx, unsigned char* result); +void keccak_256(const unsigned char* data, size_t len, unsigned char* digest); +void keccak_512(const unsigned char* data, size_t len, unsigned char* digest); +#endif + +void sha3_256(const unsigned char* data, size_t len, unsigned char* digest); +void sha3_512(const unsigned char* data, size_t len, unsigned char* digest); + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* __SHA3_H__ */ diff --git a/applications/external/flipbip/lib/crypto/shamir.c b/applications/external/flipbip/lib/crypto/shamir.c new file mode 100644 index 000000000..037af99cc --- /dev/null +++ b/applications/external/flipbip/lib/crypto/shamir.c @@ -0,0 +1,338 @@ +/* + * Implementation of the hazardous parts of the SSS library + * + * Copyright (c) 2017 Daan Sprenkels + * Copyright (c) 2019 SatoshiLabs + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * This code contains the actual Shamir secret sharing functionality. The + * implementation of this code is based on the idea that the user likes to + * generate/combine 32 shares (in GF(2^8)) at the same time, because a 256 bit + * key will be exactly 32 bytes. Therefore we bitslice all the input and + * unbitslice the output right before returning. + * + * This bitslice approach optimizes natively on all architectures that are 32 + * bit or more. Care is taken to use not too many registers, to ensure that no + * values have to be leaked to the stack. + * + * All functions in this module are implemented constant time and constant + * lookup operations, as all proper crypto code must be. + */ + +#include "shamir.h" +#include +#include "memzero.h" + +static void bitslice(uint32_t r[8], const uint8_t* x, size_t len) { + size_t bit_idx = 0, arr_idx = 0; + uint32_t cur = 0; + + memset(r, 0, sizeof(uint32_t[8])); + for(arr_idx = 0; arr_idx < len; arr_idx++) { + cur = (uint32_t)x[arr_idx]; + for(bit_idx = 0; bit_idx < 8; bit_idx++) { + r[bit_idx] |= ((cur >> bit_idx) & 1) << arr_idx; + } + } +} + +static void unbitslice(uint8_t* r, const uint32_t x[8], size_t len) { + size_t bit_idx = 0, arr_idx = 0; + uint32_t cur = 0; + + memset(r, 0, sizeof(uint8_t) * len); + for(bit_idx = 0; bit_idx < 8; bit_idx++) { + cur = (uint32_t)x[bit_idx]; + for(arr_idx = 0; arr_idx < len; arr_idx++) { + r[arr_idx] |= ((cur >> arr_idx) & 1) << bit_idx; + } + } +} + +static void bitslice_setall(uint32_t r[8], const uint8_t x) { + size_t idx = 0; + for(idx = 0; idx < 8; idx++) { + r[idx] = -((x >> idx) & 1); + } +} + +/* + * Add (XOR) `r` with `x` and store the result in `r`. + */ +static void gf256_add(uint32_t r[8], const uint32_t x[8]) { + size_t idx = 0; + for(idx = 0; idx < 8; idx++) r[idx] ^= x[idx]; +} + +/* + * Safely multiply two bitsliced polynomials in GF(2^8) reduced by + * x^8 + x^4 + x^3 + x + 1. `r` and `a` may overlap, but overlapping of `r` + * and `b` will produce an incorrect result! If you need to square a polynomial + * use `gf256_square` instead. + */ +static void gf256_mul(uint32_t r[8], const uint32_t a[8], const uint32_t b[8]) { + /* This function implements Russian Peasant multiplication on two + * bitsliced polynomials. + * + * I personally think that these kinds of long lists of operations + * are often a bit ugly. A double for loop would be nicer and would + * take up a lot less lines of code. + * However, some compilers seem to fail in optimizing these kinds of + * loops. So we will just have to do this by hand. + */ + uint32_t a2[8] = {0}; + memcpy(a2, a, sizeof(uint32_t[8])); + + r[0] = a2[0] & b[0]; /* add (assignment, because r is 0) */ + r[1] = a2[1] & b[0]; + r[2] = a2[2] & b[0]; + r[3] = a2[3] & b[0]; + r[4] = a2[4] & b[0]; + r[5] = a2[5] & b[0]; + r[6] = a2[6] & b[0]; + r[7] = a2[7] & b[0]; + a2[0] ^= a2[7]; /* reduce */ + a2[2] ^= a2[7]; + a2[3] ^= a2[7]; + + r[0] ^= a2[7] & b[1]; /* add */ + r[1] ^= a2[0] & b[1]; + r[2] ^= a2[1] & b[1]; + r[3] ^= a2[2] & b[1]; + r[4] ^= a2[3] & b[1]; + r[5] ^= a2[4] & b[1]; + r[6] ^= a2[5] & b[1]; + r[7] ^= a2[6] & b[1]; + a2[7] ^= a2[6]; /* reduce */ + a2[1] ^= a2[6]; + a2[2] ^= a2[6]; + + r[0] ^= a2[6] & b[2]; /* add */ + r[1] ^= a2[7] & b[2]; + r[2] ^= a2[0] & b[2]; + r[3] ^= a2[1] & b[2]; + r[4] ^= a2[2] & b[2]; + r[5] ^= a2[3] & b[2]; + r[6] ^= a2[4] & b[2]; + r[7] ^= a2[5] & b[2]; + a2[6] ^= a2[5]; /* reduce */ + a2[0] ^= a2[5]; + a2[1] ^= a2[5]; + + r[0] ^= a2[5] & b[3]; /* add */ + r[1] ^= a2[6] & b[3]; + r[2] ^= a2[7] & b[3]; + r[3] ^= a2[0] & b[3]; + r[4] ^= a2[1] & b[3]; + r[5] ^= a2[2] & b[3]; + r[6] ^= a2[3] & b[3]; + r[7] ^= a2[4] & b[3]; + a2[5] ^= a2[4]; /* reduce */ + a2[7] ^= a2[4]; + a2[0] ^= a2[4]; + + r[0] ^= a2[4] & b[4]; /* add */ + r[1] ^= a2[5] & b[4]; + r[2] ^= a2[6] & b[4]; + r[3] ^= a2[7] & b[4]; + r[4] ^= a2[0] & b[4]; + r[5] ^= a2[1] & b[4]; + r[6] ^= a2[2] & b[4]; + r[7] ^= a2[3] & b[4]; + a2[4] ^= a2[3]; /* reduce */ + a2[6] ^= a2[3]; + a2[7] ^= a2[3]; + + r[0] ^= a2[3] & b[5]; /* add */ + r[1] ^= a2[4] & b[5]; + r[2] ^= a2[5] & b[5]; + r[3] ^= a2[6] & b[5]; + r[4] ^= a2[7] & b[5]; + r[5] ^= a2[0] & b[5]; + r[6] ^= a2[1] & b[5]; + r[7] ^= a2[2] & b[5]; + a2[3] ^= a2[2]; /* reduce */ + a2[5] ^= a2[2]; + a2[6] ^= a2[2]; + + r[0] ^= a2[2] & b[6]; /* add */ + r[1] ^= a2[3] & b[6]; + r[2] ^= a2[4] & b[6]; + r[3] ^= a2[5] & b[6]; + r[4] ^= a2[6] & b[6]; + r[5] ^= a2[7] & b[6]; + r[6] ^= a2[0] & b[6]; + r[7] ^= a2[1] & b[6]; + a2[2] ^= a2[1]; /* reduce */ + a2[4] ^= a2[1]; + a2[5] ^= a2[1]; + + r[0] ^= a2[1] & b[7]; /* add */ + r[1] ^= a2[2] & b[7]; + r[2] ^= a2[3] & b[7]; + r[3] ^= a2[4] & b[7]; + r[4] ^= a2[5] & b[7]; + r[5] ^= a2[6] & b[7]; + r[6] ^= a2[7] & b[7]; + r[7] ^= a2[0] & b[7]; + + memzero(a2, sizeof(a2)); +} + +/* + * Square `x` in GF(2^8) and write the result to `r`. `r` and `x` may overlap. + */ +static void gf256_square(uint32_t r[8], const uint32_t x[8]) { + uint32_t r8 = 0, r10 = 0, r12 = 0, r14 = 0; + /* Use the Freshman's Dream rule to square the polynomial + * Assignments are done from 7 downto 0, because this allows the user + * to execute this function in-place (e.g. `gf256_square(r, r);`). + */ + r14 = x[7]; + r12 = x[6]; + r10 = x[5]; + r8 = x[4]; + r[6] = x[3]; + r[4] = x[2]; + r[2] = x[1]; + r[0] = x[0]; + + /* Reduce with x^8 + x^4 + x^3 + x + 1 until order is less than 8 */ + r[7] = r14; /* r[7] was 0 */ + r[6] ^= r14; + r10 ^= r14; + /* Skip, because r13 is always 0 */ + r[4] ^= r12; + r[5] = r12; /* r[5] was 0 */ + r[7] ^= r12; + r8 ^= r12; + /* Skip, because r11 is always 0 */ + r[2] ^= r10; + r[3] = r10; /* r[3] was 0 */ + r[5] ^= r10; + r[6] ^= r10; + r[1] = r14; /* r[1] was 0 */ + r[2] ^= r14; /* Substitute r9 by r14 because they will always be equal*/ + r[4] ^= r14; + r[5] ^= r14; + r[0] ^= r8; + r[1] ^= r8; + r[3] ^= r8; + r[4] ^= r8; +} + +/* + * Invert `x` in GF(2^8) and write the result to `r` + */ +static void gf256_inv(uint32_t r[8], uint32_t x[8]) { + uint32_t y[8] = {0}, z[8] = {0}; + + gf256_square(y, x); // y = x^2 + gf256_square(y, y); // y = x^4 + gf256_square(r, y); // r = x^8 + gf256_mul(z, r, x); // z = x^9 + gf256_square(r, r); // r = x^16 + gf256_mul(r, r, z); // r = x^25 + gf256_square(r, r); // r = x^50 + gf256_square(z, r); // z = x^100 + gf256_square(z, z); // z = x^200 + gf256_mul(r, r, z); // r = x^250 + gf256_mul(r, r, y); // r = x^254 + + memzero(y, sizeof(y)); + memzero(z, sizeof(z)); +} + +bool shamir_interpolate( + uint8_t* result, + uint8_t result_index, + const uint8_t* share_indices, + const uint8_t** share_values, + uint8_t share_count, + size_t len) { + size_t i = 0, j = 0; + uint32_t x[8] = {0}; + uint32_t xs[share_count][8]; + memset(xs, 0, sizeof(xs)); + uint32_t ys[share_count][8]; + memset(ys, 0, sizeof(ys)); + uint32_t num[8] = {~0}; /* num is the numerator (=1) */ + uint32_t denom[8] = {0}; + uint32_t tmp[8] = {0}; + uint32_t secret[8] = {0}; + bool ret = true; + + if(len > SHAMIR_MAX_LEN) return false; + + /* Collect the x and y values */ + for(i = 0; i < share_count; i++) { + bitslice_setall(xs[i], share_indices[i]); + bitslice(ys[i], share_values[i], len); + } + bitslice_setall(x, result_index); + + for(i = 0; i < share_count; i++) { + memcpy(tmp, x, sizeof(uint32_t[8])); + gf256_add(tmp, xs[i]); + gf256_mul(num, num, tmp); + } + + /* Use Lagrange basis polynomials to calculate the secret coefficient */ + for(i = 0; i < share_count; i++) { + /* The code below assumes that none of the share_indices are equal to + * result_index. We need to treat that as a special case. */ + if(share_indices[i] != result_index) { + memcpy(denom, x, sizeof(denom)); + gf256_add(denom, xs[i]); + } else { + bitslice_setall(denom, 1); + gf256_add(secret, ys[i]); + } + for(j = 0; j < share_count; j++) { + if(i == j) continue; + memcpy(tmp, xs[i], sizeof(uint32_t[8])); + gf256_add(tmp, xs[j]); + gf256_mul(denom, denom, tmp); + } + if((denom[0] | denom[1] | denom[2] | denom[3] | denom[4] | denom[5] | denom[6] | + denom[7]) == 0) { + /* The share_indices are not unique. */ + ret = false; + break; + } + gf256_inv(tmp, denom); /* inverted denominator */ + gf256_mul(tmp, tmp, num); /* basis polynomial */ + gf256_mul(tmp, tmp, ys[i]); /* scaled coefficient */ + gf256_add(secret, tmp); + } + + if(ret == true) { + unbitslice(result, secret, len); + } + + memzero(x, sizeof(x)); + memzero(xs, sizeof(xs)); + memzero(ys, sizeof(ys)); + memzero(num, sizeof(num)); + memzero(denom, sizeof(denom)); + memzero(tmp, sizeof(tmp)); + memzero(secret, sizeof(secret)); + return ret; +} diff --git a/applications/external/flipbip/lib/crypto/shamir.h b/applications/external/flipbip/lib/crypto/shamir.h new file mode 100644 index 000000000..2250fc672 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/shamir.h @@ -0,0 +1,73 @@ +/* + * Low level API for Daan Sprenkels' Shamir secret sharing library + * Copyright (c) 2017 Daan Sprenkels + * Copyright (c) 2019 SatoshiLabs + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Usage of this API is hazardous and is only reserved for beings with a + * good understanding of the Shamir secret sharing scheme and who know how + * crypto code is implemented. If you are unsure about this, use the + * intermediate level API. You have been warned! + */ + +#ifndef __SHAMIR_H__ +#define __SHAMIR_H__ + +#include +#include +#include + +#define SHAMIR_MAX_LEN 32 + +/* + * Computes f(x) given the Shamir shares (x_1, f(x_1)), ... , (x_m, f(x_m)). + * The x coordinates of the shares must be pairwise distinct. Returns true on + * success, otherwise false. + * result: Array of length len where the evaluations of the polynomials in x + * will be written. + * result_index: The x coordinate of the result. + * share_indices: Points to the array of integers x_1, ... , x_m. + * share_values: Points to the array of y_1, ... , y_m, where each y_i is an + * array of bytes of length len representing the evaluations of the + * polynomials in x_i. + * share_count: The number of shares m. + * len: The length of the result array and of each of the y_1, ... , y_m arrays. + * + * The number of shares used to compute the result may be larger than the + * required threshold. + * + * This function does *not* do *any* checking for integrity. If any of the + * shares are not original, this will result in an invalid restored value. + * All values written to `result` should be treated as secret. Even if some of + * the shares that were provided as input were incorrect, the result *still* + * allows an attacker to gain information about the correct result. + * + * This function treats `shares_values`, `share_indices` and `result` as secret + * values. `share_count` is treated as a public value (for performance reasons). + */ +bool shamir_interpolate( + uint8_t* result, + uint8_t result_index, + const uint8_t* share_indices, + const uint8_t** share_values, + uint8_t share_count, + size_t len); + +#endif /* __SHAMIR_H__ */ diff --git a/applications/external/flipbip/lib/crypto/slip39.c b/applications/external/flipbip/lib/crypto/slip39.c new file mode 100644 index 000000000..268d0f37e --- /dev/null +++ b/applications/external/flipbip/lib/crypto/slip39.c @@ -0,0 +1,150 @@ +/** + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "slip39.h" +#include +#include +#include "slip39_wordlist.h" + +/** + * Returns word at position `index`. + */ +const char* get_word(uint16_t index) { + if(index >= WORDS_COUNT) { + return NULL; + } + + return slip39_wordlist[index]; +} + +/** + * Finds the index of a given word. + * Returns true on success and stores result in `index`. + */ +bool word_index(uint16_t* index, const char* word, uint8_t word_length) { + uint16_t lo = 0; + uint16_t hi = WORDS_COUNT; + uint16_t mid = 0; + + while((hi - lo) > 1) { + mid = (hi + lo) / 2; + if(strncmp(slip39_wordlist[mid], word, word_length) > 0) { + hi = mid; + } else { + lo = mid; + } + } + if(strncmp(slip39_wordlist[lo], word, word_length) != 0) { + return false; + } + *index = lo; + return true; +} + +/** + * Returns the index of the first sequence in words_button_seq[] which is not + * less than the given sequence. Returns WORDS_COUNT if there is no such + * sequence. + */ +static uint16_t find_sequence(uint16_t sequence) { + if(sequence <= words_button_seq[0].sequence) { + return 0; + } + + uint16_t lo = 0; + uint16_t hi = WORDS_COUNT; + + while(hi - lo > 1) { + uint16_t mid = (hi + lo) / 2; + if(words_button_seq[mid].sequence >= sequence) { + hi = mid; + } else { + lo = mid; + } + } + + return hi; +} + +/** + * Returns a word matching the button sequence prefix or NULL if no match is + * found. + */ +const char* button_sequence_to_word(uint16_t sequence) { + if(sequence == 0) { + return slip39_wordlist[words_button_seq[0].index]; + } + + uint16_t multiplier = 1; + while(sequence < 1000) { + sequence *= 10; + multiplier *= 10; + } + + uint16_t i = find_sequence(sequence); + if(i >= WORDS_COUNT || words_button_seq[i].sequence - sequence >= multiplier) { + return NULL; + } + + return slip39_wordlist[words_button_seq[i].index]; +} + +/** + * Calculates which buttons on the T9 keyboard can still be pressed after the + * prefix was entered. Returns a 9-bit bitmask, where each bit specifies which + * buttons can be pressed (there are still words in this combination). The least + * significant bit corresponds to the first button. + * + * Example: 110000110 - second, third, eighth and ninth button still can be + * pressed. + */ +uint16_t slip39_word_completion_mask(uint16_t prefix) { + if(prefix >= 1000) { + // Four char prefix -> the mask is zero. + return 0; + } + + // Determine the range of sequences [min, max), which have the given prefix. + uint16_t min = prefix; + uint16_t max = prefix + 1; + uint16_t divider = 1; + while(max <= 1000) { + min *= 10; + max *= 10; + divider *= 10; + } + divider /= 10; + + // Determine the range we will be searching in words_button_seq[]. + min = find_sequence(min); + max = find_sequence(max); + + uint16_t bitmap = 0; + for(uint16_t i = min; i < max; ++i) { + uint8_t digit = (words_button_seq[i].sequence / divider) % 10; + bitmap |= 1 << (digit - 1); + } + + return bitmap; +} diff --git a/applications/external/flipbip/lib/crypto/slip39.h b/applications/external/flipbip/lib/crypto/slip39.h new file mode 100644 index 000000000..0bc24fa74 --- /dev/null +++ b/applications/external/flipbip/lib/crypto/slip39.h @@ -0,0 +1,39 @@ +/** + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __SLIP39_H__ +#define __SLIP39_H__ + +#include +#include + +const char* get_word(uint16_t index); + +bool word_index(uint16_t* index, const char* word, uint8_t word_length); + +uint16_t slip39_word_completion_mask(uint16_t prefix); + +const char* button_sequence_to_word(uint16_t prefix); + +#endif diff --git a/applications/external/flipbip/lib/crypto/slip39_wordlist.h b/applications/external/flipbip/lib/crypto/slip39_wordlist.h new file mode 100644 index 000000000..17d4edeed --- /dev/null +++ b/applications/external/flipbip/lib/crypto/slip39_wordlist.h @@ -0,0 +1,1203 @@ +/** + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __SLIP39_WORDLIST_H__ +#define __SLIP39_WORDLIST_H__ + +#include + +#define WORDS_COUNT 1024 + +static const char* const slip39_wordlist[WORDS_COUNT] = { + "academic", "acid", "acne", "acquire", "acrobat", "activity", "actress", "adapt", + "adequate", "adjust", "admit", "adorn", "adult", "advance", "advocate", "afraid", + "again", "agency", "agree", "aide", "aircraft", "airline", "airport", "ajar", + "alarm", "album", "alcohol", "alien", "alive", "alpha", "already", "alto", + "aluminum", "always", "amazing", "ambition", "amount", "amuse", "analysis", "anatomy", + "ancestor", "ancient", "angel", "angry", "animal", "answer", "antenna", "anxiety", + "apart", "aquatic", "arcade", "arena", "argue", "armed", "artist", "artwork", + "aspect", "auction", "august", "aunt", "average", "aviation", "avoid", "award", + "away", "axis", "axle", "beam", "beard", "beaver", "become", "bedroom", + "behavior", "being", "believe", "belong", "benefit", "best", "beyond", "bike", + "biology", "birthday", "bishop", "black", "blanket", "blessing", "blimp", "blind", + "blue", "body", "bolt", "boring", "born", "both", "boundary", "bracelet", + "branch", "brave", "breathe", "briefing", "broken", "brother", "browser", "bucket", + "budget", "building", "bulb", "bulge", "bumpy", "bundle", "burden", "burning", + "busy", "buyer", "cage", "calcium", "camera", "campus", "canyon", "capacity", + "capital", "capture", "carbon", "cards", "careful", "cargo", "carpet", "carve", + "category", "cause", "ceiling", "center", "ceramic", "champion", "change", "charity", + "check", "chemical", "chest", "chew", "chubby", "cinema", "civil", "class", + "clay", "cleanup", "client", "climate", "clinic", "clock", "clogs", "closet", + "clothes", "club", "cluster", "coal", "coastal", "coding", "column", "company", + "corner", "costume", "counter", "course", "cover", "cowboy", "cradle", "craft", + "crazy", "credit", "cricket", "criminal", "crisis", "critical", "crowd", "crucial", + "crunch", "crush", "crystal", "cubic", "cultural", "curious", "curly", "custody", + "cylinder", "daisy", "damage", "dance", "darkness", "database", "daughter", "deadline", + "deal", "debris", "debut", "decent", "decision", "declare", "decorate", "decrease", + "deliver", "demand", "density", "deny", "depart", "depend", "depict", "deploy", + "describe", "desert", "desire", "desktop", "destroy", "detailed", "detect", "device", + "devote", "diagnose", "dictate", "diet", "dilemma", "diminish", "dining", "diploma", + "disaster", "discuss", "disease", "dish", "dismiss", "display", "distance", "dive", + "divorce", "document", "domain", "domestic", "dominant", "dough", "downtown", "dragon", + "dramatic", "dream", "dress", "drift", "drink", "drove", "drug", "dryer", + "duckling", "duke", "duration", "dwarf", "dynamic", "early", "earth", "easel", + "easy", "echo", "eclipse", "ecology", "edge", "editor", "educate", "either", + "elbow", "elder", "election", "elegant", "element", "elephant", "elevator", "elite", + "else", "email", "emerald", "emission", "emperor", "emphasis", "employer", "empty", + "ending", "endless", "endorse", "enemy", "energy", "enforce", "engage", "enjoy", + "enlarge", "entrance", "envelope", "envy", "epidemic", "episode", "equation", "equip", + "eraser", "erode", "escape", "estate", "estimate", "evaluate", "evening", "evidence", + "evil", "evoke", "exact", "example", "exceed", "exchange", "exclude", "excuse", + "execute", "exercise", "exhaust", "exotic", "expand", "expect", "explain", "express", + "extend", "extra", "eyebrow", "facility", "fact", "failure", "faint", "fake", + "false", "family", "famous", "fancy", "fangs", "fantasy", "fatal", "fatigue", + "favorite", "fawn", "fiber", "fiction", "filter", "finance", "findings", "finger", + "firefly", "firm", "fiscal", "fishing", "fitness", "flame", "flash", "flavor", + "flea", "flexible", "flip", "float", "floral", "fluff", "focus", "forbid", + "force", "forecast", "forget", "formal", "fortune", "forward", "founder", "fraction", + "fragment", "frequent", "freshman", "friar", "fridge", "friendly", "frost", "froth", + "frozen", "fumes", "funding", "furl", "fused", "galaxy", "game", "garbage", + "garden", "garlic", "gasoline", "gather", "general", "genius", "genre", "genuine", + "geology", "gesture", "glad", "glance", "glasses", "glen", "glimpse", "goat", + "golden", "graduate", "grant", "grasp", "gravity", "gray", "greatest", "grief", + "grill", "grin", "grocery", "gross", "group", "grownup", "grumpy", "guard", + "guest", "guilt", "guitar", "gums", "hairy", "hamster", "hand", "hanger", + "harvest", "have", "havoc", "hawk", "hazard", "headset", "health", "hearing", + "heat", "helpful", "herald", "herd", "hesitate", "hobo", "holiday", "holy", + "home", "hormone", "hospital", "hour", "huge", "human", "humidity", "hunting", + "husband", "hush", "husky", "hybrid", "idea", "identify", "idle", "image", + "impact", "imply", "improve", "impulse", "include", "income", "increase", "index", + "indicate", "industry", "infant", "inform", "inherit", "injury", "inmate", "insect", + "inside", "install", "intend", "intimate", "invasion", "involve", "iris", "island", + "isolate", "item", "ivory", "jacket", "jerky", "jewelry", "join", "judicial", + "juice", "jump", "junction", "junior", "junk", "jury", "justice", "kernel", + "keyboard", "kidney", "kind", "kitchen", "knife", "knit", "laden", "ladle", + "ladybug", "lair", "lamp", "language", "large", "laser", "laundry", "lawsuit", + "leader", "leaf", "learn", "leaves", "lecture", "legal", "legend", "legs", + "lend", "length", "level", "liberty", "library", "license", "lift", "likely", + "lilac", "lily", "lips", "liquid", "listen", "literary", "living", "lizard", + "loan", "lobe", "location", "losing", "loud", "loyalty", "luck", "lunar", + "lunch", "lungs", "luxury", "lying", "lyrics", "machine", "magazine", "maiden", + "mailman", "main", "makeup", "making", "mama", "manager", "mandate", "mansion", + "manual", "marathon", "march", "market", "marvel", "mason", "material", "math", + "maximum", "mayor", "meaning", "medal", "medical", "member", "memory", "mental", + "merchant", "merit", "method", "metric", "midst", "mild", "military", "mineral", + "minister", "miracle", "mixed", "mixture", "mobile", "modern", "modify", "moisture", + "moment", "morning", "mortgage", "mother", "mountain", "mouse", "move", "much", + "mule", "multiple", "muscle", "museum", "music", "mustang", "nail", "national", + "necklace", "negative", "nervous", "network", "news", "nuclear", "numb", "numerous", + "nylon", "oasis", "obesity", "object", "observe", "obtain", "ocean", "often", + "olympic", "omit", "oral", "orange", "orbit", "order", "ordinary", "organize", + "ounce", "oven", "overall", "owner", "paces", "pacific", "package", "paid", + "painting", "pajamas", "pancake", "pants", "papa", "paper", "parcel", "parking", + "party", "patent", "patrol", "payment", "payroll", "peaceful", "peanut", "peasant", + "pecan", "penalty", "pencil", "percent", "perfect", "permit", "petition", "phantom", + "pharmacy", "photo", "phrase", "physics", "pickup", "picture", "piece", "pile", + "pink", "pipeline", "pistol", "pitch", "plains", "plan", "plastic", "platform", + "playoff", "pleasure", "plot", "plunge", "practice", "prayer", "preach", "predator", + "pregnant", "premium", "prepare", "presence", "prevent", "priest", "primary", "priority", + "prisoner", "privacy", "prize", "problem", "process", "profile", "program", "promise", + "prospect", "provide", "prune", "public", "pulse", "pumps", "punish", "puny", + "pupal", "purchase", "purple", "python", "quantity", "quarter", "quick", "quiet", + "race", "racism", "radar", "railroad", "rainbow", "raisin", "random", "ranked", + "rapids", "raspy", "reaction", "realize", "rebound", "rebuild", "recall", "receiver", + "recover", "regret", "regular", "reject", "relate", "remember", "remind", "remove", + "render", "repair", "repeat", "replace", "require", "rescue", "research", "resident", + "response", "result", "retailer", "retreat", "reunion", "revenue", "review", "reward", + "rhyme", "rhythm", "rich", "rival", "river", "robin", "rocky", "romantic", + "romp", "roster", "round", "royal", "ruin", "ruler", "rumor", "sack", + "safari", "salary", "salon", "salt", "satisfy", "satoshi", "saver", "says", + "scandal", "scared", "scatter", "scene", "scholar", "science", "scout", "scramble", + "screw", "script", "scroll", "seafood", "season", "secret", "security", "segment", + "senior", "shadow", "shaft", "shame", "shaped", "sharp", "shelter", "sheriff", + "short", "should", "shrimp", "sidewalk", "silent", "silver", "similar", "simple", + "single", "sister", "skin", "skunk", "slap", "slavery", "sled", "slice", + "slim", "slow", "slush", "smart", "smear", "smell", "smirk", "smith", + "smoking", "smug", "snake", "snapshot", "sniff", "society", "software", "soldier", + "solution", "soul", "source", "space", "spark", "speak", "species", "spelling", + "spend", "spew", "spider", "spill", "spine", "spirit", "spit", "spray", + "sprinkle", "square", "squeeze", "stadium", "staff", "standard", "starting", "station", + "stay", "steady", "step", "stick", "stilt", "story", "strategy", "strike", + "style", "subject", "submit", "sugar", "suitable", "sunlight", "superior", "surface", + "surprise", "survive", "sweater", "swimming", "swing", "switch", "symbolic", "sympathy", + "syndrome", "system", "tackle", "tactics", "tadpole", "talent", "task", "taste", + "taught", "taxi", "teacher", "teammate", "teaspoon", "temple", "tenant", "tendency", + "tension", "terminal", "testify", "texture", "thank", "that", "theater", "theory", + "therapy", "thorn", "threaten", "thumb", "thunder", "ticket", "tidy", "timber", + "timely", "ting", "tofu", "together", "tolerate", "total", "toxic", "tracks", + "traffic", "training", "transfer", "trash", "traveler", "treat", "trend", "trial", + "tricycle", "trip", "triumph", "trouble", "true", "trust", "twice", "twin", + "type", "typical", "ugly", "ultimate", "umbrella", "uncover", "undergo", "unfair", + "unfold", "unhappy", "union", "universe", "unkind", "unknown", "unusual", "unwrap", + "upgrade", "upstairs", "username", "usher", "usual", "valid", "valuable", "vampire", + "vanish", "various", "vegan", "velvet", "venture", "verdict", "verify", "very", + "veteran", "vexed", "victim", "video", "view", "vintage", "violence", "viral", + "visitor", "visual", "vitamins", "vocal", "voice", "volume", "voter", "voting", + "walnut", "warmth", "warn", "watch", "wavy", "wealthy", "weapon", "webcam", + "welcome", "welfare", "western", "width", "wildlife", "window", "wine", "wireless", + "wisdom", "withdraw", "wits", "wolf", "woman", "work", "worthy", "wrap", + "wrist", "writing", "wrote", "year", "yelp", "yield", "yoga", "zero", +}; + +/** + * This array contains number representations of SLIP-39 words. + * These numbers are determined how the words were entered on a + * T9 keyboard with the following layout: + * ab (1) cd (2) ef (3) + * ghij (4) klm (5) nopq (6) + * rs (7) tuv (8) wxyz (9) + * + * Each word is uniquely defined by four buttons. + */ +static const struct { + uint16_t sequence; + uint16_t index; +} words_button_seq[WORDS_COUNT] = { + {1212, 0}, // academic + {1216, 7}, // adapt + {1236, 8}, // adequate + {1242, 1}, // acid + {1248, 9}, // adjust + {1254, 10}, // admit + {1263, 2}, // acne + {1267, 11}, // adorn + {1268, 3}, // acquire + {1276, 4}, // acrobat + {1281, 13}, // advance + {1284, 5}, // activity + {1285, 12}, // adult + {1286, 14}, // advocate + {1287, 6}, // actress + {1315, 67}, // beam + {1317, 68}, // beard + {1318, 69}, // beaver + {1326, 70}, // become + {1327, 71}, // bedroom + {1341, 72}, // behavior + {1346, 73}, // being + {1354, 74}, // believe + {1356, 75}, // belong + {1363, 76}, // benefit + {1371, 15}, // afraid + {1378, 77}, // best + {1396, 78}, // beyond + {1414, 16}, // again + {1417, 23}, // ajar + {1423, 19}, // aide + {1436, 17}, // agency + {1453, 79}, // bike + {1465, 80}, // biology + {1472, 20}, // aircraft + {1473, 18}, // agree + {1474, 82}, // bishop + {1475, 21}, // airline + {1476, 22}, // airport + {1478, 81}, // birthday + {1512, 83}, // black + {1514, 35}, // ambition + {1516, 84}, // blanket + {1517, 24}, // alarm + {1518, 25}, // album + {1519, 34}, // amazing + {1526, 26}, // alcohol + {1537, 85}, // blessing + {1543, 27}, // alien + {1545, 86}, // blimp + {1546, 87}, // blind + {1548, 28}, // alive + {1564, 29}, // alpha + {1568, 36}, // amount + {1573, 30}, // already + {1583, 88}, // blue + {1585, 32}, // aluminum + {1586, 31}, // alto + {1587, 37}, // amuse + {1591, 33}, // always + {1615, 38}, // analysis + {1617, 48}, // apart + {1618, 39}, // anatomy + {1623, 40}, // ancestor + {1624, 41}, // ancient + {1629, 89}, // body + {1643, 42}, // angel + {1645, 44}, // animal + {1647, 43}, // angry + {1658, 90}, // bolt + {1674, 91}, // boring + {1676, 92}, // born + {1679, 45}, // answer + {1681, 49}, // aquatic + {1683, 46}, // antenna + {1684, 93}, // both + {1686, 94}, // boundary + {1694, 47}, // anxiety + {1712, 95}, // bracelet + {1716, 96}, // branch + {1718, 97}, // brave + {1721, 50}, // arcade + {1731, 98}, // breathe + {1736, 51}, // arena + {1743, 99}, // briefing + {1748, 52}, // argue + {1753, 53}, // armed + {1763, 56}, // aspect + {1765, 100}, // broken + {1768, 101}, // brother + {1769, 102}, // browser + {1784, 54}, // artist + {1789, 55}, // artwork + {1824, 104}, // budget + {1825, 103}, // bucket + {1828, 57}, // auction + {1837, 60}, // average + {1841, 61}, // aviation + {1845, 105}, // building + {1848, 58}, // august + {1851, 106}, // bulb + {1854, 107}, // bulge + {1856, 108}, // bumpy + {1862, 109}, // bundle + {1864, 62}, // avoid + {1868, 59}, // aunt + {1872, 110}, // burden + {1876, 111}, // burning + {1879, 112}, // busy + {1893, 113}, // buyer + {1917, 63}, // award + {1919, 64}, // away + {1947, 65}, // axis + {1953, 66}, // axle + {2143, 114}, // cage + {2147, 185}, // daisy + {2151, 186}, // damage + {2152, 115}, // calcium + {2153, 116}, // camera + {2156, 117}, // campus + {2161, 119}, // capacity + {2162, 187}, // dance + {2164, 120}, // capital + {2168, 121}, // capture + {2169, 118}, // canyon + {2171, 122}, // carbon + {2172, 123}, // cards + {2173, 124}, // careful + {2174, 125}, // cargo + {2175, 188}, // darkness + {2176, 126}, // carpet + {2178, 127}, // carve + {2181, 189}, // database + {2183, 128}, // category + {2184, 190}, // daughter + {2187, 129}, // cause + {2312, 191}, // deadline + {2315, 192}, // deal + {2317, 193}, // debris + {2318, 194}, // debut + {2323, 195}, // decent + {2324, 196}, // decision + {2325, 197}, // declare + {2326, 198}, // decorate + {2327, 199}, // decrease + {2345, 130}, // ceiling + {2351, 201}, // demand + {2354, 200}, // deliver + {2361, 204}, // depart + {2363, 205}, // depend + {2364, 206}, // depict + {2365, 207}, // deploy + {2367, 202}, // density + {2368, 131}, // center + {2369, 203}, // deny + {2371, 132}, // ceramic + {2372, 208}, // describe + {2373, 209}, // desert + {2374, 210}, // desire + {2375, 211}, // desktop + {2378, 212}, // destroy + {2381, 213}, // detailed + {2383, 214}, // detect + {2384, 215}, // device + {2386, 216}, // devote + {2414, 217}, // diagnose + {2415, 133}, // champion + {2416, 134}, // change + {2417, 135}, // charity + {2428, 218}, // dictate + {2432, 136}, // check + {2435, 137}, // chemical + {2437, 138}, // chest + {2438, 219}, // diet + {2439, 139}, // chew + {2453, 220}, // dilemma + {2454, 221}, // diminish + {2463, 141}, // cinema + {2464, 222}, // dining + {2465, 223}, // diploma + {2471, 224}, // disaster + {2472, 225}, // discuss + {2473, 226}, // disease + {2474, 227}, // dish + {2475, 228}, // dismiss + {2476, 229}, // display + {2478, 230}, // distance + {2481, 140}, // chubby + {2483, 231}, // dive + {2484, 142}, // civil + {2486, 232}, // divorce + {2517, 143}, // class + {2519, 144}, // clay + {2531, 145}, // cleanup + {2543, 146}, // client + {2545, 147}, // climate + {2546, 148}, // clinic + {2562, 149}, // clock + {2564, 150}, // clogs + {2567, 151}, // closet + {2568, 152}, // clothes + {2581, 153}, // club + {2587, 154}, // cluster + {2615, 155}, // coal + {2617, 156}, // coastal + {2624, 157}, // coding + {2628, 233}, // document + {2651, 234}, // domain + {2653, 235}, // domestic + {2654, 236}, // dominant + {2656, 159}, // company + {2658, 158}, // column + {2676, 160}, // corner + {2678, 161}, // costume + {2683, 164}, // cover + {2684, 237}, // dough + {2686, 162}, // counter + {2687, 163}, // course + {2691, 165}, // cowboy + {2696, 238}, // downtown + {2712, 166}, // cradle + {2713, 167}, // craft + {2714, 239}, // dragon + {2715, 240}, // dramatic + {2719, 168}, // crazy + {2731, 241}, // dream + {2732, 169}, // credit + {2737, 242}, // dress + {2742, 170}, // cricket + {2743, 243}, // drift + {2745, 171}, // criminal + {2746, 244}, // drink + {2747, 172}, // crisis + {2748, 173}, // critical + {2768, 245}, // drove + {2769, 174}, // crowd + {2782, 175}, // crucial + {2784, 246}, // drug + {2786, 176}, // crunch + {2787, 177}, // crush + {2793, 247}, // dryer + {2797, 178}, // crystal + {2814, 179}, // cubic + {2825, 248}, // duckling + {2853, 249}, // duke + {2858, 180}, // cultural + {2871, 250}, // duration + {2874, 181}, // curious + {2875, 182}, // curly + {2878, 183}, // custody + {2917, 251}, // dwarf + {2954, 184}, // cylinder + {2961, 252}, // dynamic + {3124, 323}, // facility + {3128, 324}, // fact + {3145, 325}, // failure + {3146, 326}, // faint + {3153, 327}, // fake + {3154, 329}, // family + {3156, 330}, // famous + {3157, 328}, // false + {3162, 331}, // fancy + {3164, 332}, // fangs + {3168, 333}, // fantasy + {3173, 255}, // easel + {3175, 253}, // early + {3178, 254}, // earth + {3179, 256}, // easy + {3181, 334}, // fatal + {3184, 335}, // fatigue + {3186, 336}, // favorite + {3196, 337}, // fawn + {3243, 260}, // edge + {3246, 257}, // echo + {3248, 261}, // editor + {3254, 258}, // eclipse + {3265, 259}, // ecology + {3282, 262}, // educate + {3413, 338}, // fiber + {3428, 339}, // fiction + {3458, 340}, // filter + {3461, 341}, // finance + {3462, 342}, // findings + {3464, 343}, // finger + {3472, 346}, // fiscal + {3473, 344}, // firefly + {3474, 347}, // fishing + {3475, 345}, // firm + {3484, 263}, // either + {3486, 348}, // fitness + {3514, 273}, // email + {3515, 349}, // flame + {3516, 264}, // elbow + {3517, 350}, // flash + {3518, 351}, // flavor + {3523, 265}, // elder + {3531, 352}, // flea + {3532, 266}, // election + {3534, 267}, // elegant + {3535, 268}, // element + {3536, 269}, // elephant + {3537, 274}, // emerald + {3538, 270}, // elevator + {3539, 353}, // flexible + {3546, 354}, // flip + {3547, 275}, // emission + {3548, 271}, // elite + {3561, 355}, // float + {3563, 276}, // emperor + {3564, 277}, // emphasis + {3565, 278}, // employer + {3567, 356}, // floral + {3568, 279}, // empty + {3573, 272}, // else + {3583, 357}, // fluff + {3624, 280}, // ending + {3625, 281}, // endless + {3626, 282}, // endorse + {3628, 358}, // focus + {3635, 283}, // enemy + {3636, 285}, // enforce + {3637, 284}, // energy + {3641, 286}, // engage + {3642, 292}, // epidemic + {3646, 287}, // enjoy + {3647, 293}, // episode + {3651, 288}, // enlarge + {3671, 359}, // forbid + {3672, 360}, // force + {3673, 361}, // forecast + {3674, 362}, // forget + {3675, 363}, // formal + {3678, 364}, // fortune + {3679, 365}, // forward + {3681, 294}, // equation + {3683, 290}, // envelope + {3684, 295}, // equip + {3686, 366}, // founder + {3687, 289}, // entrance + {3689, 291}, // envy + {3712, 367}, // fraction + {3714, 368}, // fragment + {3717, 296}, // eraser + {3721, 298}, // escape + {3736, 369}, // frequent + {3737, 370}, // freshman + {3741, 371}, // friar + {3742, 372}, // fridge + {3743, 373}, // friendly + {3762, 297}, // erode + {3767, 374}, // frost + {3768, 375}, // froth + {3769, 376}, // frozen + {3781, 299}, // estate + {3784, 300}, // estimate + {3815, 301}, // evaluate + {3836, 302}, // evening + {3842, 303}, // evidence + {3845, 304}, // evil + {3853, 377}, // fumes + {3862, 378}, // funding + {3865, 305}, // evoke + {3873, 380}, // fused + {3875, 379}, // furl + {3912, 306}, // exact + {3915, 307}, // example + {3923, 308}, // exceed + {3924, 309}, // exchange + {3925, 310}, // exclude + {3928, 311}, // excuse + {3931, 322}, // eyebrow + {3932, 312}, // execute + {3937, 313}, // exercise + {3941, 314}, // exhaust + {3961, 316}, // expand + {3963, 317}, // expect + {3965, 318}, // explain + {3967, 319}, // express + {3968, 315}, // exotic + {3983, 320}, // extend + {3987, 321}, // extra + {4125, 483}, // jacket + {4147, 420}, // hairy + {4151, 381}, // galaxy + {4153, 382}, // game + {4157, 421}, // hamster + {4162, 422}, // hand + {4164, 423}, // hanger + {4171, 383}, // garbage + {4172, 384}, // garden + {4175, 385}, // garlic + {4176, 386}, // gasoline + {4178, 424}, // harvest + {4183, 425}, // have + {4184, 387}, // gather + {4186, 426}, // havoc + {4191, 428}, // hazard + {4195, 427}, // hawk + {4231, 452}, // idea + {4236, 453}, // identify + {4253, 454}, // idle + {4312, 429}, // headset + {4315, 430}, // health + {4317, 431}, // hearing + {4318, 432}, // heat + {4356, 433}, // helpful + {4363, 388}, // general + {4364, 389}, // genius + {4365, 392}, // geology + {4367, 390}, // genre + {4368, 391}, // genuine + {4371, 434}, // herald + {4372, 435}, // herd + {4374, 436}, // hesitate + {4375, 484}, // jerky + {4378, 393}, // gesture + {4393, 485}, // jewelry + {4512, 394}, // glad + {4514, 455}, // image + {4516, 395}, // glance + {4517, 396}, // glasses + {4536, 397}, // glen + {4545, 398}, // glimpse + {4561, 456}, // impact + {4565, 457}, // imply + {4567, 458}, // improve + {4568, 459}, // impulse + {4616, 437}, // hobo + {4618, 399}, // goat + {4623, 463}, // index + {4624, 464}, // indicate + {4625, 460}, // include + {4626, 461}, // income + {4627, 462}, // increase + {4628, 465}, // industry + {4631, 466}, // infant + {4636, 467}, // inform + {4643, 468}, // inherit + {4646, 486}, // join + {4648, 469}, // injury + {4651, 470}, // inmate + {4652, 400}, // golden + {4653, 440}, // home + {4654, 438}, // holiday + {4659, 439}, // holy + {4673, 471}, // insect + {4674, 472}, // inside + {4675, 441}, // hormone + {4676, 442}, // hospital + {4678, 473}, // install + {4681, 476}, // invasion + {4683, 474}, // intend + {4684, 475}, // intimate + {4686, 477}, // involve + {4687, 443}, // hour + {4712, 401}, // graduate + {4716, 402}, // grant + {4717, 403}, // grasp + {4718, 404}, // gravity + {4719, 405}, // gray + {4731, 406}, // greatest + {4743, 407}, // grief + {4745, 408}, // grill + {4746, 409}, // grin + {4747, 478}, // iris + {4751, 479}, // island + {4762, 410}, // grocery + {4765, 480}, // isolate + {4767, 411}, // gross + {4768, 412}, // group + {4769, 413}, // grownup + {4785, 414}, // grumpy + {4817, 415}, // guard + {4824, 487}, // judicial + {4835, 481}, // item + {4837, 416}, // guest + {4842, 488}, // juice + {4843, 444}, // huge + {4845, 417}, // guilt + {4848, 418}, // guitar + {4851, 445}, // human + {4854, 446}, // humidity + {4856, 489}, // jump + {4857, 419}, // gums + {4862, 490}, // junction + {4864, 491}, // junior + {4865, 492}, // junk + {4867, 482}, // ivory + {4868, 447}, // hunting + {4871, 448}, // husband + {4874, 449}, // hush + {4875, 450}, // husky + {4878, 494}, // justice + {4879, 493}, // jury + {4917, 451}, // hybrid + {5123, 502}, // laden + {5124, 549}, // machine + {5125, 503}, // ladle + {5129, 504}, // ladybug + {5141, 550}, // magazine + {5142, 551}, // maiden + {5145, 552}, // mailman + {5146, 553}, // main + {5147, 505}, // lair + {5151, 556}, // mama + {5153, 554}, // makeup + {5154, 555}, // making + {5156, 506}, // lamp + {5161, 557}, // manager + {5162, 558}, // mandate + {5164, 507}, // language + {5167, 559}, // mansion + {5168, 560}, // manual + {5171, 561}, // marathon + {5172, 562}, // march + {5173, 509}, // laser + {5174, 508}, // large + {5175, 563}, // market + {5176, 565}, // mason + {5178, 564}, // marvel + {5183, 566}, // material + {5184, 567}, // math + {5186, 510}, // laundry + {5194, 568}, // maximum + {5196, 569}, // mayor + {5197, 511}, // lawsuit + {5312, 512}, // leader + {5313, 513}, // leaf + {5316, 570}, // meaning + {5317, 514}, // learn + {5318, 515}, // leaves + {5321, 571}, // medal + {5324, 572}, // medical + {5328, 516}, // lecture + {5341, 517}, // legal + {5343, 518}, // legend + {5347, 519}, // legs + {5351, 573}, // member + {5356, 574}, // memory + {5362, 520}, // lend + {5364, 521}, // length + {5368, 575}, // mental + {5372, 576}, // merchant + {5374, 577}, // merit + {5376, 495}, // kernel + {5383, 522}, // level + {5384, 578}, // method + {5387, 579}, // metric + {5391, 496}, // keyboard + {5413, 523}, // liberty + {5417, 524}, // library + {5423, 525}, // license + {5426, 497}, // kidney + {5427, 580}, // midst + {5438, 526}, // lift + {5451, 528}, // lilac + {5452, 581}, // mild + {5453, 527}, // likely + {5454, 582}, // military + {5459, 529}, // lily + {5462, 498}, // kind + {5463, 583}, // mineral + {5464, 584}, // minister + {5467, 530}, // lips + {5468, 531}, // liquid + {5471, 585}, // miracle + {5478, 532}, // listen + {5482, 499}, // kitchen + {5483, 533}, // literary + {5484, 534}, // living + {5491, 535}, // lizard + {5493, 586}, // mixed + {5498, 587}, // mixture + {5613, 537}, // lobe + {5614, 588}, // mobile + {5616, 536}, // loan + {5621, 538}, // location + {5623, 589}, // modern + {5624, 590}, // modify + {5643, 500}, // knife + {5647, 591}, // moisture + {5648, 501}, // knit + {5653, 592}, // moment + {5674, 539}, // losing + {5676, 593}, // morning + {5678, 594}, // mortgage + {5682, 540}, // loud + {5683, 598}, // move + {5684, 595}, // mother + {5686, 596}, // mountain + {5687, 597}, // mouse + {5691, 541}, // loyalty + {5824, 599}, // much + {5825, 542}, // luck + {5853, 600}, // mule + {5858, 601}, // multiple + {5861, 543}, // lunar + {5862, 544}, // lunch + {5864, 545}, // lungs + {5872, 602}, // muscle + {5873, 603}, // museum + {5874, 604}, // music + {5878, 605}, // mustang + {5898, 546}, // luxury + {5946, 547}, // lying + {5974, 548}, // lyrics + {6123, 636}, // paces + {6124, 637}, // pacific + {6125, 638}, // package + {6137, 618}, // obesity + {6141, 641}, // pajamas + {6142, 639}, // paid + {6143, 619}, // object + {6145, 606}, // nail + {6146, 640}, // painting + {6161, 644}, // papa + {6162, 642}, // pancake + {6163, 645}, // paper + {6168, 643}, // pants + {6172, 646}, // parcel + {6173, 620}, // observe + {6174, 617}, // oasis + {6175, 647}, // parking + {6178, 648}, // party + {6181, 621}, // obtain + {6183, 649}, // patent + {6184, 607}, // national + {6187, 650}, // patrol + {6195, 651}, // payment + {6197, 652}, // payroll + {6231, 622}, // ocean + {6312, 653}, // peaceful + {6316, 654}, // peanut + {6317, 655}, // peasant + {6321, 656}, // pecan + {6325, 608}, // necklace + {6341, 609}, // negative + {6361, 657}, // penalty + {6362, 658}, // pencil + {6372, 659}, // percent + {6373, 660}, // perfect + {6375, 661}, // permit + {6378, 610}, // nervous + {6383, 623}, // often + {6384, 662}, // petition + {6389, 611}, // network + {6397, 612}, // news + {6416, 663}, // phantom + {6417, 664}, // pharmacy + {6425, 668}, // pickup + {6428, 669}, // picture + {6432, 670}, // piece + {6453, 671}, // pile + {6463, 673}, // pipeline + {6465, 672}, // pink + {6468, 665}, // photo + {6471, 666}, // phrase + {6478, 674}, // pistol + {6482, 675}, // pitch + {6497, 667}, // physics + {6514, 676}, // plains + {6516, 677}, // plan + {6517, 678}, // plastic + {6518, 679}, // platform + {6519, 680}, // playoff + {6531, 681}, // pleasure + {6548, 625}, // omit + {6568, 682}, // plot + {6586, 683}, // plunge + {6595, 624}, // olympic + {6712, 684}, // practice + {6714, 628}, // orbit + {6715, 626}, // oral + {6716, 627}, // orange + {6719, 685}, // prayer + {6723, 629}, // order + {6724, 630}, // ordinary + {6731, 686}, // preach + {6732, 687}, // predator + {6734, 688}, // pregnant + {6735, 689}, // premium + {6736, 690}, // prepare + {6737, 691}, // presence + {6738, 692}, // prevent + {6741, 631}, // organize + {6743, 693}, // priest + {6745, 694}, // primary + {6746, 695}, // priority + {6747, 696}, // prisoner + {6748, 697}, // privacy + {6749, 698}, // prize + {6761, 699}, // problem + {6762, 700}, // process + {6763, 701}, // profile + {6764, 702}, // program + {6765, 703}, // promise + {6767, 704}, // prospect + {6768, 705}, // provide + {6786, 706}, // prune + {6815, 707}, // public + {6816, 716}, // quantity + {6817, 717}, // quarter + {6825, 613}, // nuclear + {6836, 633}, // oven + {6837, 634}, // overall + {6842, 718}, // quick + {6843, 719}, // quiet + {6851, 614}, // numb + {6853, 615}, // numerous + {6856, 709}, // pumps + {6857, 708}, // pulse + {6861, 712}, // pupal + {6862, 632}, // ounce + {6864, 710}, // punish + {6869, 711}, // puny + {6872, 713}, // purchase + {6876, 714}, // purple + {6956, 616}, // nylon + {6963, 635}, // owner + {6984, 715}, // python + {7121, 722}, // radar + {7123, 720}, // race + {7124, 721}, // racism + {7125, 775}, // sack + {7131, 776}, // safari + {7145, 723}, // railroad + {7146, 724}, // rainbow + {7147, 725}, // raisin + {7151, 777}, // salary + {7156, 778}, // salon + {7158, 779}, // salt + {7162, 726}, // random + {7164, 728}, // rapids + {7165, 727}, // ranked + {7176, 729}, // raspy + {7183, 782}, // saver + {7184, 780}, // satisfy + {7186, 781}, // satoshi + {7197, 783}, // says + {7216, 784}, // scandal + {7217, 785}, // scared + {7218, 786}, // scatter + {7236, 787}, // scene + {7243, 789}, // science + {7246, 788}, // scholar + {7268, 790}, // scout + {7271, 791}, // scramble + {7273, 792}, // screw + {7274, 793}, // script + {7276, 794}, // scroll + {7312, 730}, // reaction + {7313, 795}, // seafood + {7315, 731}, // realize + {7316, 732}, // rebound + {7317, 796}, // season + {7318, 733}, // rebuild + {7321, 734}, // recall + {7323, 735}, // receiver + {7326, 736}, // recover + {7327, 797}, // secret + {7328, 798}, // security + {7343, 739}, // reject + {7345, 799}, // segment + {7347, 737}, // regret + {7348, 738}, // regular + {7351, 740}, // relate + {7353, 741}, // remember + {7354, 742}, // remind + {7356, 743}, // remove + {7361, 745}, // repair + {7362, 744}, // render + {7363, 746}, // repeat + {7364, 800}, // senior + {7365, 747}, // replace + {7368, 748}, // require + {7372, 749}, // rescue + {7373, 750}, // research + {7374, 751}, // resident + {7376, 752}, // response + {7378, 753}, // result + {7381, 754}, // retailer + {7383, 757}, // revenue + {7384, 758}, // review + {7386, 756}, // reunion + {7387, 755}, // retreat + {7391, 759}, // reward + {7412, 801}, // shadow + {7413, 802}, // shaft + {7415, 803}, // shame + {7416, 804}, // shaped + {7417, 805}, // sharp + {7423, 811}, // sidewalk + {7424, 762}, // rich + {7435, 806}, // shelter + {7437, 807}, // sheriff + {7453, 812}, // silent + {7454, 814}, // similar + {7456, 815}, // simple + {7458, 813}, // silver + {7464, 816}, // single + {7467, 808}, // short + {7468, 809}, // should + {7474, 810}, // shrimp + {7478, 817}, // sister + {7481, 763}, // rival + {7483, 764}, // river + {7495, 760}, // rhyme + {7498, 761}, // rhythm + {7516, 820}, // slap + {7517, 827}, // smart + {7518, 821}, // slavery + {7531, 828}, // smear + {7532, 822}, // sled + {7535, 829}, // smell + {7542, 823}, // slice + {7545, 824}, // slim + {7546, 818}, // skin + {7547, 830}, // smirk + {7548, 831}, // smith + {7565, 832}, // smoking + {7569, 825}, // slow + {7584, 833}, // smug + {7586, 819}, // skunk + {7587, 826}, // slush + {7612, 843}, // space + {7614, 765}, // robin + {7615, 834}, // snake + {7616, 835}, // snapshot + {7617, 844}, // spark + {7624, 837}, // society + {7625, 766}, // rocky + {7631, 845}, // speak + {7632, 846}, // species + {7635, 847}, // spelling + {7636, 848}, // spend + {7638, 838}, // software + {7639, 849}, // spew + {7642, 850}, // spider + {7643, 836}, // sniff + {7645, 851}, // spill + {7646, 852}, // spine + {7647, 853}, // spirit + {7648, 854}, // spit + {7651, 767}, // romantic + {7652, 839}, // soldier + {7656, 768}, // romp + {7658, 840}, // solution + {7671, 855}, // spray + {7674, 856}, // sprinkle + {7678, 769}, // roster + {7681, 857}, // square + {7683, 858}, // squeeze + {7685, 841}, // soul + {7686, 770}, // round + {7687, 842}, // source + {7691, 771}, // royal + {7812, 859}, // stadium + {7813, 860}, // staff + {7814, 873}, // subject + {7815, 874}, // submit + {7816, 861}, // standard + {7817, 862}, // starting + {7818, 863}, // station + {7819, 864}, // stay + {7831, 865}, // steady + {7836, 866}, // step + {7841, 875}, // sugar + {7842, 867}, // stick + {7845, 868}, // stilt + {7846, 772}, // ruin + {7848, 876}, // suitable + {7853, 773}, // ruler + {7856, 774}, // rumor + {7863, 878}, // superior + {7865, 877}, // sunlight + {7867, 869}, // story + {7871, 870}, // strategy + {7873, 879}, // surface + {7874, 871}, // strike + {7876, 880}, // surprise + {7878, 881}, // survive + {7895, 872}, // style + {7931, 882}, // sweater + {7945, 883}, // swimming + {7946, 884}, // swing + {7948, 885}, // switch + {7951, 886}, // symbolic + {7956, 887}, // sympathy + {7962, 888}, // syndrome + {7978, 889}, // system + {8125, 890}, // tackle + {8126, 892}, // tadpole + {8128, 891}, // tactics + {8153, 893}, // talent + {8154, 965}, // valid + {8156, 967}, // vampire + {8158, 966}, // valuable + {8164, 968}, // vanish + {8174, 969}, // various + {8175, 894}, // task + {8178, 895}, // taste + {8184, 896}, // taught + {8194, 897}, // taxi + {8312, 898}, // teacher + {8315, 899}, // teammate + {8317, 900}, // teaspoon + {8341, 970}, // vegan + {8356, 901}, // temple + {8358, 971}, // velvet + {8361, 902}, // tenant + {8362, 903}, // tendency + {8367, 904}, // tension + {8368, 972}, // venture + {8372, 973}, // verdict + {8374, 974}, // verify + {8375, 905}, // terminal + {8378, 906}, // testify + {8379, 975}, // very + {8383, 976}, // veteran + {8393, 977}, // vexed + {8398, 907}, // texture + {8416, 908}, // thank + {8418, 909}, // that + {8423, 979}, // video + {8425, 917}, // ticket + {8428, 978}, // victim + {8429, 918}, // tidy + {8431, 910}, // theater + {8436, 911}, // theory + {8437, 912}, // therapy + {8439, 980}, // view + {8451, 919}, // timber + {8453, 920}, // timely + {8459, 946}, // ugly + {8464, 921}, // ting + {8465, 982}, // violence + {8467, 913}, // thorn + {8468, 981}, // vintage + {8471, 983}, // viral + {8473, 914}, // threaten + {8474, 984}, // visitor + {8478, 985}, // visual + {8481, 986}, // vitamins + {8485, 915}, // thumb + {8486, 916}, // thunder + {8517, 948}, // umbrella + {8584, 947}, // ultimate + {8621, 987}, // vocal + {8623, 950}, // undergo + {8626, 949}, // uncover + {8631, 951}, // unfair + {8636, 952}, // unfold + {8638, 922}, // tofu + {8641, 953}, // unhappy + {8642, 988}, // voice + {8643, 923}, // together + {8646, 954}, // union + {8647, 960}, // upgrade + {8648, 955}, // universe + {8653, 924}, // tolerate + {8654, 956}, // unkind + {8656, 957}, // unknown + {8658, 989}, // volume + {8678, 961}, // upstairs + {8681, 925}, // total + {8683, 990}, // voter + {8684, 991}, // voting + {8687, 958}, // unusual + {8694, 926}, // toxic + {8697, 959}, // unwrap + {8712, 927}, // tracks + {8713, 928}, // traffic + {8714, 929}, // training + {8716, 930}, // transfer + {8717, 931}, // trash + {8718, 932}, // traveler + {8731, 933}, // treat + {8736, 934}, // trend + {8737, 962}, // username + {8741, 935}, // trial + {8742, 936}, // tricycle + {8743, 963}, // usher + {8746, 937}, // trip + {8748, 938}, // triumph + {8768, 939}, // trouble + {8781, 964}, // usual + {8783, 940}, // true + {8787, 941}, // trust + {8942, 942}, // twice + {8946, 943}, // twin + {8963, 944}, // type + {8964, 945}, // typical + {9156, 992}, // walnut + {9175, 993}, // warmth + {9176, 994}, // warn + {9182, 995}, // watch + {9189, 996}, // wavy + {9312, 999}, // webcam + {9315, 997}, // wealthy + {9316, 998}, // weapon + {9317, 1019}, // year + {9352, 1000}, // welcome + {9353, 1001}, // welfare + {9356, 1020}, // yelp + {9376, 1023}, // zero + {9378, 1002}, // western + {9428, 1003}, // width + {9435, 1021}, // yield + {9452, 1004}, // wildlife + {9462, 1005}, // window + {9463, 1006}, // wine + {9472, 1008}, // wisdom + {9473, 1007}, // wireless + {9484, 1009}, // withdraw + {9487, 1010}, // wits + {9641, 1022}, // yoga + {9651, 1012}, // woman + {9653, 1011}, // wolf + {9675, 1013}, // work + {9678, 1014}, // worthy + {9716, 1015}, // wrap + {9747, 1016}, // wrist + {9748, 1017}, // writing + {9768, 1018}, // wrote +}; + +#endif diff --git a/applications/external/flipbip/scenes/flipbip_scene.c b/applications/external/flipbip/scenes/flipbip_scene.c new file mode 100644 index 000000000..d3656a868 --- /dev/null +++ b/applications/external/flipbip/scenes/flipbip_scene.c @@ -0,0 +1,30 @@ +#include "flipbip_scene.h" + +// Generate scene on_enter handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, +void (*const flipbip_on_enter_handlers[])(void*) = { +#include "flipbip_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_event handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, +bool (*const flipbip_on_event_handlers[])(void* context, SceneManagerEvent event) = { +#include "flipbip_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_exit handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, +void (*const flipbip_on_exit_handlers[])(void* context) = { +#include "flipbip_scene_config.h" +}; +#undef ADD_SCENE + +// Initialize scene handlers configuration structure +const SceneManagerHandlers flipbip_scene_handlers = { + .on_enter_handlers = flipbip_on_enter_handlers, + .on_event_handlers = flipbip_on_event_handlers, + .on_exit_handlers = flipbip_on_exit_handlers, + .scene_num = FlipBipSceneNum, +}; diff --git a/applications/external/flipbip/scenes/flipbip_scene.h b/applications/external/flipbip/scenes/flipbip_scene.h new file mode 100644 index 000000000..fd49b44c0 --- /dev/null +++ b/applications/external/flipbip/scenes/flipbip_scene.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +// Generate scene id and total number +#define ADD_SCENE(prefix, name, id) FlipBipScene##id, +typedef enum { +#include "flipbip_scene_config.h" + FlipBipSceneNum, +} FlipBipScene; +#undef ADD_SCENE + +extern const SceneManagerHandlers flipbip_scene_handlers; + +// Generate scene on_enter handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); +#include "flipbip_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_event handlers declaration +#define ADD_SCENE(prefix, name, id) \ + bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event); +#include "flipbip_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_exit handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context); +#include "flipbip_scene_config.h" +#undef ADD_SCENE diff --git a/applications/external/flipbip/scenes/flipbip_scene_config.h b/applications/external/flipbip/scenes/flipbip_scene_config.h new file mode 100644 index 000000000..a62832162 --- /dev/null +++ b/applications/external/flipbip/scenes/flipbip_scene_config.h @@ -0,0 +1,4 @@ +ADD_SCENE(flipbip, startscreen, Startscreen) +ADD_SCENE(flipbip, menu, Menu) +ADD_SCENE(flipbip, scene_1, Scene_1) +ADD_SCENE(flipbip, settings, Settings) \ No newline at end of file diff --git a/applications/external/flipbip/scenes/flipbip_scene_menu.c b/applications/external/flipbip/scenes/flipbip_scene_menu.c new file mode 100644 index 000000000..04525909d --- /dev/null +++ b/applications/external/flipbip/scenes/flipbip_scene_menu.c @@ -0,0 +1,130 @@ +#include "../flipbip.h" +#include "../helpers/flipbip_file.h" + +enum SubmenuIndex { + SubmenuIndexScene1BTC = 10, + SubmenuIndexScene1ETH, + SubmenuIndexScene1DOGE, + SubmenuIndexScene1New, + SubmenuIndexScene1Import, + SubmenuIndexSettings, +}; + +void flipbip_scene_menu_submenu_callback(void* context, uint32_t index) { + FlipBip* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, index); +} + +void flipbip_scene_menu_on_enter(void* context) { + FlipBip* app = context; + + if(flipbip_has_file(FlipBipFileKey, NULL, false) && + flipbip_has_file(FlipBipFileDat, NULL, false)) { + submenu_add_item( + app->submenu, + "View BTC wallet", + SubmenuIndexScene1BTC, + flipbip_scene_menu_submenu_callback, + app); + submenu_add_item( + app->submenu, + "View ETH wallet", + SubmenuIndexScene1ETH, + flipbip_scene_menu_submenu_callback, + app); + submenu_add_item( + app->submenu, + "View DOGE wallet", + SubmenuIndexScene1DOGE, + flipbip_scene_menu_submenu_callback, + app); + submenu_add_item( + app->submenu, + "Regenerate wallet", + SubmenuIndexScene1New, + flipbip_scene_menu_submenu_callback, + app); + } else { + submenu_add_item( + app->submenu, + "Generate new wallet", + SubmenuIndexScene1New, + flipbip_scene_menu_submenu_callback, + app); + } + submenu_add_item( + app->submenu, + "Import from mnemonic", + SubmenuIndexScene1Import, + flipbip_scene_menu_submenu_callback, + app); + + submenu_add_item( + app->submenu, "Settings", SubmenuIndexSettings, flipbip_scene_menu_submenu_callback, app); + + submenu_set_selected_item( + app->submenu, scene_manager_get_scene_state(app->scene_manager, FlipBipSceneMenu)); + + view_dispatcher_switch_to_view(app->view_dispatcher, FlipBipViewIdMenu); +} + +bool flipbip_scene_menu_on_event(void* context, SceneManagerEvent event) { + FlipBip* app = context; + //UNUSED(app); + if(event.type == SceneManagerEventTypeBack) { + //exit app + scene_manager_stop(app->scene_manager); + view_dispatcher_stop(app->view_dispatcher); + return true; + } else if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexScene1BTC) { + app->overwrite_saved_seed = 0; + app->import_from_mnemonic = 0; + app->bip44_coin = FlipBipCoinBTC0; + scene_manager_set_scene_state( + app->scene_manager, FlipBipSceneMenu, SubmenuIndexScene1BTC); + scene_manager_next_scene(app->scene_manager, FlipBipSceneScene_1); + return true; + } else if(event.event == SubmenuIndexScene1ETH) { + app->overwrite_saved_seed = 0; + app->import_from_mnemonic = 0; + app->bip44_coin = FlipBipCoinETH60; + scene_manager_set_scene_state( + app->scene_manager, FlipBipSceneMenu, SubmenuIndexScene1ETH); + scene_manager_next_scene(app->scene_manager, FlipBipSceneScene_1); + return true; + } else if(event.event == SubmenuIndexScene1DOGE) { + app->overwrite_saved_seed = 0; + app->import_from_mnemonic = 0; + app->bip44_coin = FlipBipCoinDOGE3; + scene_manager_set_scene_state( + app->scene_manager, FlipBipSceneMenu, SubmenuIndexScene1DOGE); + scene_manager_next_scene(app->scene_manager, FlipBipSceneScene_1); + return true; + } else if(event.event == SubmenuIndexScene1New) { + app->overwrite_saved_seed = 1; + app->import_from_mnemonic = 0; + scene_manager_set_scene_state( + app->scene_manager, FlipBipSceneMenu, SubmenuIndexScene1New); + scene_manager_next_scene(app->scene_manager, FlipBipSceneScene_1); + return true; + } else if(event.event == SubmenuIndexScene1Import) { + app->import_from_mnemonic = 1; + app->input_state = FlipBipTextInputMnemonic; + text_input_set_header_text(app->text_input, "Enter mnemonic phrase"); + view_dispatcher_switch_to_view(app->view_dispatcher, FlipBipViewIdTextInput); + return true; + } else if(event.event == SubmenuIndexSettings) { + scene_manager_set_scene_state( + app->scene_manager, FlipBipSceneMenu, SubmenuIndexSettings); + scene_manager_next_scene(app->scene_manager, FlipBipSceneSettings); + return true; + } + } + return false; +} + +void flipbip_scene_menu_on_exit(void* context) { + FlipBip* app = context; + submenu_reset(app->submenu); +} \ No newline at end of file diff --git a/applications/external/flipbip/scenes/flipbip_scene_scene_1.c b/applications/external/flipbip/scenes/flipbip_scene_scene_1.c new file mode 100644 index 000000000..6f4064cd4 --- /dev/null +++ b/applications/external/flipbip/scenes/flipbip_scene_scene_1.c @@ -0,0 +1,50 @@ +#include "../flipbip.h" +#include "../helpers/flipbip_custom_event.h" +#include "../views/flipbip_scene_1.h" + +void flipbip_scene_1_callback(FlipBipCustomEvent event, void* context) { + furi_assert(context); + FlipBip* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, event); +} + +void flipbip_scene_scene_1_on_enter(void* context) { + furi_assert(context); + FlipBip* app = context; + flipbip_scene_1_set_callback(app->flipbip_scene_1, flipbip_scene_1_callback, app); + view_dispatcher_switch_to_view(app->view_dispatcher, FlipBipViewIdScene1); +} + +bool flipbip_scene_scene_1_on_event(void* context, SceneManagerEvent event) { + FlipBip* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + switch(event.event) { + case FlipBipCustomEventScene1Left: + case FlipBipCustomEventScene1Right: + break; + case FlipBipCustomEventScene1Up: + case FlipBipCustomEventScene1Down: + break; + case FlipBipCustomEventScene1Back: + notification_message(app->notification, &sequence_reset_red); + notification_message(app->notification, &sequence_reset_green); + notification_message(app->notification, &sequence_reset_blue); + if(!scene_manager_search_and_switch_to_previous_scene( + app->scene_manager, FlipBipSceneMenu)) { + scene_manager_stop(app->scene_manager); + view_dispatcher_stop(app->view_dispatcher); + } + consumed = true; + break; + } + } + + return consumed; +} + +void flipbip_scene_scene_1_on_exit(void* context) { + FlipBip* app = context; + UNUSED(app); +} \ No newline at end of file diff --git a/applications/external/flipbip/scenes/flipbip_scene_settings.c b/applications/external/flipbip/scenes/flipbip_scene_settings.c new file mode 100644 index 000000000..c743c97b8 --- /dev/null +++ b/applications/external/flipbip/scenes/flipbip_scene_settings.c @@ -0,0 +1,141 @@ +#include "../flipbip.h" +#include +// From: lib/crypto +#include + +#define TEXT_LABEL_ON "ON" +#define TEXT_LABEL_OFF "OFF" + +const char* const haptic_text[2] = { + TEXT_LABEL_OFF, + TEXT_LABEL_ON, +}; +const uint32_t haptic_value[2] = { + FlipBipHapticOff, + FlipBipHapticOn, +}; + +const char* const led_text[2] = { + TEXT_LABEL_OFF, + TEXT_LABEL_ON, +}; +const uint32_t led_value[2] = { + FlipBipLedOff, + FlipBipLedOn, +}; + +const char* const bip39_strength_text[3] = { + "12", + "18", + "24", +}; +const uint32_t bip39_strength_value[3] = { + FlipBipStrength128, + FlipBipStrength192, + FlipBipStrength256, +}; + +const char* const passphrase_text[2] = { + TEXT_LABEL_OFF, + TEXT_LABEL_ON, +}; +const uint32_t passphrase_value[2] = { + FlipBipPassphraseOff, + FlipBipPassphraseOn, +}; + +static void flipbip_scene_settings_set_haptic(VariableItem* item) { + FlipBip* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + variable_item_set_current_value_text(item, haptic_text[index]); + app->haptic = haptic_value[index]; +} + +static void flipbip_scene_settings_set_led(VariableItem* item) { + FlipBip* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + variable_item_set_current_value_text(item, led_text[index]); + app->led = led_value[index]; +} + +static void flipbip_scene_settings_set_bip39_strength(VariableItem* item) { + FlipBip* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + variable_item_set_current_value_text(item, bip39_strength_text[index]); + app->bip39_strength = bip39_strength_value[index]; +} + +static void flipbip_scene_settings_set_passphrase(VariableItem* item) { + FlipBip* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + variable_item_set_current_value_text(item, passphrase_text[index]); + app->passphrase = passphrase_value[index]; + + if(app->passphrase == FlipBipPassphraseOn) { + app->input_state = FlipBipTextInputPassphrase; + text_input_set_header_text(app->text_input, "Enter BIP39 passphrase"); + view_dispatcher_switch_to_view(app->view_dispatcher, FlipBipViewIdTextInput); + } else { + memzero(app->passphrase_text, TEXT_BUFFER_SIZE); + } +} + +void flipbip_scene_settings_submenu_callback(void* context, uint32_t index) { + FlipBip* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, index); +} + +void flipbip_scene_settings_on_enter(void* context) { + FlipBip* app = context; + VariableItem* item; + uint8_t value_index; + + // BIP39 strength + item = variable_item_list_add( + app->variable_item_list, "BIP39 Words:", 3, flipbip_scene_settings_set_bip39_strength, app); + value_index = value_index_uint32(app->bip39_strength, bip39_strength_value, 3); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, bip39_strength_text[value_index]); + + // Passphrase + item = variable_item_list_add( + app->variable_item_list, + "BIP39 Passphrase:", + 2, + flipbip_scene_settings_set_passphrase, + app); + value_index = value_index_uint32(app->passphrase, passphrase_value, 2); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, passphrase_text[value_index]); + + // Vibro on/off + item = variable_item_list_add( + app->variable_item_list, "Vibro/Haptic:", 2, flipbip_scene_settings_set_haptic, app); + value_index = value_index_uint32(app->haptic, haptic_value, 2); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, haptic_text[value_index]); + + // LED Effects on/off + item = variable_item_list_add( + app->variable_item_list, "LED FX:", 2, flipbip_scene_settings_set_led, app); + value_index = value_index_uint32(app->led, led_value, 2); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, led_text[value_index]); + + view_dispatcher_switch_to_view(app->view_dispatcher, FlipBipViewIdSettings); +} + +bool flipbip_scene_settings_on_event(void* context, SceneManagerEvent event) { + FlipBip* app = context; + UNUSED(app); + bool consumed = false; + if(event.type == SceneManagerEventTypeCustom) { + } + return consumed; +} + +void flipbip_scene_settings_on_exit(void* context) { + FlipBip* app = context; + variable_item_list_set_selected_item(app->variable_item_list, 0); + variable_item_list_reset(app->variable_item_list); +} \ No newline at end of file diff --git a/applications/external/flipbip/scenes/flipbip_scene_startscreen.c b/applications/external/flipbip/scenes/flipbip_scene_startscreen.c new file mode 100644 index 000000000..a9cb8ba5f --- /dev/null +++ b/applications/external/flipbip/scenes/flipbip_scene_startscreen.c @@ -0,0 +1,55 @@ +#include "../flipbip.h" +#include "../helpers/flipbip_custom_event.h" +#include "../views/flipbip_startscreen.h" + +void flipbip_scene_startscreen_callback(FlipBipCustomEvent event, void* context) { + furi_assert(context); + FlipBip* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, event); +} + +void flipbip_scene_startscreen_on_enter(void* context) { + furi_assert(context); + FlipBip* app = context; + flipbip_startscreen_set_callback( + app->flipbip_startscreen, flipbip_scene_startscreen_callback, app); + view_dispatcher_switch_to_view(app->view_dispatcher, FlipBipViewIdStartscreen); +} + +bool flipbip_scene_startscreen_on_event(void* context, SceneManagerEvent event) { + FlipBip* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + switch(event.event) { + case FlipBipCustomEventStartscreenLeft: + case FlipBipCustomEventStartscreenRight: + break; + case FlipBipCustomEventStartscreenUp: + case FlipBipCustomEventStartscreenDown: + break; + case FlipBipCustomEventStartscreenOk: + scene_manager_next_scene(app->scene_manager, FlipBipSceneMenu); + consumed = true; + break; + case FlipBipCustomEventStartscreenBack: + notification_message(app->notification, &sequence_reset_red); + notification_message(app->notification, &sequence_reset_green); + notification_message(app->notification, &sequence_reset_blue); + if(!scene_manager_search_and_switch_to_previous_scene( + app->scene_manager, FlipBipSceneStartscreen)) { + scene_manager_stop(app->scene_manager); + view_dispatcher_stop(app->view_dispatcher); + } + consumed = true; + break; + } + } + + return consumed; +} + +void flipbip_scene_startscreen_on_exit(void* context) { + FlipBip* app = context; + UNUSED(app); +} \ No newline at end of file diff --git a/applications/external/flipbip/views/flipbip_scene_1.c b/applications/external/flipbip/views/flipbip_scene_1.c new file mode 100644 index 000000000..361e9c5b4 --- /dev/null +++ b/applications/external/flipbip/views/flipbip_scene_1.c @@ -0,0 +1,723 @@ +#include "../flipbip.h" +#include +#include +#include +#include +//#include +#include +#include +#include "flipbip_icons.h" +#include "../helpers/flipbip_haptic.h" +#include "../helpers/flipbip_led.h" +#include "../helpers/flipbip_string.h" +#include "../helpers/flipbip_file.h" +// From: /lib/crypto +#include +#include +#include +#include +#include + +#define DERIV_PURPOSE 44 +#define DERIV_ACCOUNT 0 +#define DERIV_CHANGE 0 + +#define MAX_ADDR_LEN 42 + 1 // 42 = max length of address + null terminator +#define NUM_ADDRS 6 + +#define PAGE_LOADING 0 +#define PAGE_INFO 1 +#define PAGE_MNEMONIC 2 +#define PAGE_SEED 3 +#define PAGE_XPRV_ROOT 4 +#define PAGE_XPRV_ACCT 5 +#define PAGE_XPUB_ACCT 6 +#define PAGE_XPRV_EXTD 7 +#define PAGE_XPUB_EXTD 8 +#define PAGE_ADDR_BEGIN 9 +#define PAGE_ADDR_END (PAGE_ADDR_BEGIN + NUM_ADDRS - 1) + +#define TEXT_LOADING "Loading..." +#define TEXT_NEW_WALLET "New wallet" +#define TEXT_DEFAULT_COIN "Coin" +#define TEXT_RECEIVE_ADDRESS "receive address:" +#define TEXT_DEFAULT_DERIV "m/44'/X'/0'/0" +const char* TEXT_INFO = "-Scroll pages with up/down-" + "p1,2) Mnemonic/Seed " + "p3) xprv Root Key " + "p4,5) xprv/xpub Accnt Keys" + "p6,7) xprv/xpub Extnd Keys" + "p8+) Receive Addresses "; + +// #define TEXT_SAVE_QR "Save QR" +#define TEXT_QRFILE_EXT ".qrcode" // 7 chars + 1 null + +// bip44_coin, xprv_version, xpub_version, addr_version, wif_version, addr_format +const uint32_t COIN_INFO_ARRAY[3][6] = { + {COIN_BTC, 0x0488ade4, 0x0488b21e, 0x00, 0x80, FlipBipCoinBTC0}, + {COIN_ETH, 0x0488ade4, 0x0488b21e, 0x00, 0x80, FlipBipCoinETH60}, + {COIN_DOGE, 0x02fac398, 0x02facafd, 0x1e, 0x9e, FlipBipCoinBTC0}}; + +// coin_name, derivation_path +const char* COIN_TEXT_ARRAY[3][3] = { + {"BTC", "m/44'/0'/0'/0", "bitcoin:"}, + {"ETH", "m/44'/60'/0'/0", "ethereum:"}, + {"DOGE", "m/44'/3'/0'/0", "dogecoin:"}}; + +struct FlipBipScene1 { + View* view; + FlipBipScene1Callback callback; + void* context; +}; +typedef struct { + int page; + int strength; + uint32_t coin; + bool overwrite; + bool mnemonic_only; + CONFIDENTIAL const char* mnemonic; + CONFIDENTIAL uint8_t seed[64]; + CONFIDENTIAL const HDNode* node; + CONFIDENTIAL const char* xprv_root; + CONFIDENTIAL const char* xprv_account; + CONFIDENTIAL const char* xpub_account; + CONFIDENTIAL const char* xprv_extended; + CONFIDENTIAL const char* xpub_extended; + char* recv_addresses[NUM_ADDRS]; +} FlipBipScene1Model; + +// Node for the receive address +static CONFIDENTIAL HDNode* s_addr_node = NULL; +// Generic display text +static CONFIDENTIAL char* s_disp_text1 = NULL; +static CONFIDENTIAL char* s_disp_text2 = NULL; +static CONFIDENTIAL char* s_disp_text3 = NULL; +static CONFIDENTIAL char* s_disp_text4 = NULL; +static CONFIDENTIAL char* s_disp_text5 = NULL; +static CONFIDENTIAL char* s_disp_text6 = NULL; +// Derivation path text +static const char* s_derivation_text = TEXT_DEFAULT_DERIV; +//static bool s_busy = false; + +void flipbip_scene_1_set_callback( + FlipBipScene1* instance, + FlipBipScene1Callback callback, + void* context) { + furi_assert(instance); + furi_assert(callback); + instance->callback = callback; + instance->context = context; +} + +static void flipbip_scene_1_init_address( + char* addr_text, + const HDNode* node, + uint32_t coin_type, + uint32_t addr_index) { + //s_busy = true; + + // Buffer for address serialization + const size_t buflen = 40; + char buf[40 + 1] = {0}; + + // Use static node for address generation + memcpy(s_addr_node, node, sizeof(HDNode)); + memzero(addr_text, MAX_ADDR_LEN); + + hdnode_private_ckd(s_addr_node, addr_index); + hdnode_fill_public_key(s_addr_node); + + // coin info + // bip44_coin, xprv_version, xpub_version, addr_version, wif_version, addr_format + uint32_t coin_info[6] = {0}; + for(size_t i = 0; i < 6; i++) { + coin_info[i] = COIN_INFO_ARRAY[coin_type][i]; + } + + if(coin_info[5] == FlipBipCoinBTC0) { // BTC / DOGE style address + // BTC / DOGE style address + ecdsa_get_address( + s_addr_node->public_key, coin_info[3], HASHER_SHA2_RIPEMD, HASHER_SHA2D, buf, buflen); + strcpy(addr_text, buf); + + //ecdsa_get_wif(addr_node->private_key, WIF_VERSION, HASHER_SHA2D, buf, buflen); + + } else if(coin_info[5] == FlipBipCoinETH60) { // ETH + // ETH style address + hdnode_get_ethereum_pubkeyhash(s_addr_node, (uint8_t*)buf); + addr_text[0] = '0'; + addr_text[1] = 'x'; + // Convert the hash to a hex string + flipbip_btox((uint8_t*)buf, 20, addr_text + 2); + } + + // Clear the address node + memzero(s_addr_node, sizeof(HDNode)); + + //s_busy = false; +} + +static void flipbip_scene_1_draw_generic(const char* text, size_t line_len) { + // Split the text into parts + for(size_t si = 1; si <= 6; si++) { + char* ptr = NULL; + + if(si == 1) + ptr = s_disp_text1; + else if(si == 2) + ptr = s_disp_text2; + else if(si == 3) + ptr = s_disp_text3; + else if(si == 4) + ptr = s_disp_text4; + else if(si == 5) + ptr = s_disp_text5; + else if(si == 6) + ptr = s_disp_text6; + + memzero(ptr, 30 + 1); + if(line_len > 30) { + strncpy(ptr, text + ((si - 1) * 30), 30); + } else { + strncpy(ptr, text + ((si - 1) * line_len), line_len); + } + } +} + +static void flipbip_scene_1_draw_mnemonic(const char* mnemonic) { + // Delineate sections of the mnemonic every 4 words + const size_t mnemonic_working_len = strlen(mnemonic) + 1; + char* mnemonic_working = malloc(mnemonic_working_len); + strcpy(mnemonic_working, mnemonic); + int word = 0; + for(size_t i = 0; i < strlen(mnemonic_working); i++) { + if(mnemonic_working[i] == ' ') { + word++; + if(word % 4 == 0) { + mnemonic_working[i] = ','; + } + } + } + + // Split the mnemonic into parts + char* mnemonic_part = flipbip_strtok(mnemonic_working, ","); + int mi = 0; + while(mnemonic_part != NULL) { + char* ptr = NULL; + mi++; + + if(mi == 1) + ptr = s_disp_text1; + else if(mi == 2) + ptr = s_disp_text2; + else if(mi == 3) + ptr = s_disp_text3; + else if(mi == 4) + ptr = s_disp_text4; + else if(mi == 5) + ptr = s_disp_text5; + else if(mi == 6) + ptr = s_disp_text6; + + memzero(ptr, 30 + 1); + if(strlen(mnemonic_part) > 30) { + strncpy(ptr, mnemonic_part, 30); + } else { + strncpy(ptr, mnemonic_part, strlen(mnemonic_part)); + } + + mnemonic_part = flipbip_strtok(NULL, ","); + } + + // Free the working mnemonic memory + memzero(mnemonic_working, mnemonic_working_len); + free(mnemonic_working); +} + +static void flipbip_scene_1_draw_seed(FlipBipScene1Model* const model) { + const size_t seed_working_len = 64 * 2 + 1; + char* seed_working = malloc(seed_working_len); + // Convert the seed to a hex string + flipbip_btox(model->seed, 64, seed_working); + + flipbip_scene_1_draw_generic(seed_working, 22); + + // Free the working seed memory + memzero(seed_working, seed_working_len); + free(seed_working); +} + +static void flipbip_scene_1_clear_text() { + memzero((void*)s_disp_text1, 30 + 1); + memzero((void*)s_disp_text2, 30 + 1); + memzero((void*)s_disp_text3, 30 + 1); + memzero((void*)s_disp_text4, 30 + 1); + memzero((void*)s_disp_text5, 30 + 1); + memzero((void*)s_disp_text6, 30 + 1); +} + +void flipbip_scene_1_draw(Canvas* canvas, FlipBipScene1Model* model) { + //UNUSED(model); + canvas_clear(canvas); + canvas_set_color(canvas, ColorBlack); + + flipbip_scene_1_clear_text(); + if(model->page == PAGE_INFO) { + flipbip_scene_1_draw_generic(TEXT_INFO, 27); + } else if(model->page == PAGE_MNEMONIC) { + flipbip_scene_1_draw_mnemonic(model->mnemonic); + } else if(model->page == PAGE_SEED) { + flipbip_scene_1_draw_seed(model); + } else if(model->page == PAGE_XPRV_ROOT) { + flipbip_scene_1_draw_generic(model->xprv_root, 20); + } else if(model->page == PAGE_XPRV_ACCT) { + flipbip_scene_1_draw_generic(model->xprv_account, 20); + } else if(model->page == PAGE_XPUB_ACCT) { + flipbip_scene_1_draw_generic(model->xpub_account, 20); + } else if(model->page == PAGE_XPRV_EXTD) { + flipbip_scene_1_draw_generic(model->xprv_extended, 20); + } else if(model->page == PAGE_XPUB_EXTD) { + flipbip_scene_1_draw_generic(model->xpub_extended, 20); + } else if(model->page >= PAGE_ADDR_BEGIN && model->page <= PAGE_ADDR_END) { + uint32_t line_len = 12; + if(model->coin == FlipBipCoinETH60) { + line_len = 14; + } + flipbip_scene_1_draw_generic( + model->recv_addresses[model->page - PAGE_ADDR_BEGIN], line_len); + } + + if(model->page == PAGE_LOADING) { + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, 2, 10, TEXT_LOADING); + canvas_draw_str(canvas, 7, 30, s_derivation_text); + canvas_draw_icon(canvas, 86, 25, &I_Keychain_39x36); + } else if(model->page >= PAGE_ADDR_BEGIN && model->page <= PAGE_ADDR_END) { + // draw address header + canvas_set_font(canvas, FontSecondary); + // coin_name, derivation_path + const char* receive_text = COIN_TEXT_ARRAY[model->coin][0]; + if(receive_text == NULL) { + receive_text = TEXT_DEFAULT_COIN; + } + const size_t receive_len = strlen(receive_text) * 7; + canvas_draw_str_aligned(canvas, 2, 2, AlignLeft, AlignTop, receive_text); + canvas_draw_str_aligned( + canvas, receive_len + 1, 2, AlignLeft, AlignTop, TEXT_RECEIVE_ADDRESS); + + // draw address number + const unsigned char addr_num[1] = {(unsigned char)(model->page - PAGE_ADDR_BEGIN)}; + char addr_num_text[3] = {0}; + flipbip_btox(addr_num, 1, addr_num_text); + addr_num_text[0] = '/'; + canvas_draw_str_aligned(canvas, 125, 2, AlignRight, AlignTop, addr_num_text); + + // draw QR code file path + char addr_name_text[14] = {0}; + strcpy(addr_name_text, COIN_TEXT_ARRAY[model->coin][0]); + flipbip_btox(addr_num, 1, addr_name_text + strlen(addr_name_text)); + strcpy(addr_name_text + strlen(addr_name_text), TEXT_QRFILE_EXT); + //elements_button_right(canvas, addr_name_text); + canvas_draw_str_aligned(canvas, 125, 53, AlignRight, AlignTop, addr_name_text); + + // draw address + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, 7, 22, s_disp_text1); + canvas_draw_str(canvas, 7, 34, s_disp_text2); + canvas_draw_str(canvas, 7, 46, s_disp_text3); + canvas_draw_str(canvas, 7, 58, s_disp_text4); + } else { + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned(canvas, 1, 2, AlignLeft, AlignTop, s_disp_text1); + canvas_draw_str_aligned(canvas, 1, 12, AlignLeft, AlignTop, s_disp_text2); + canvas_draw_str_aligned(canvas, 1, 22, AlignLeft, AlignTop, s_disp_text3); + canvas_draw_str_aligned(canvas, 1, 32, AlignLeft, AlignTop, s_disp_text4); + canvas_draw_str_aligned(canvas, 1, 42, AlignLeft, AlignTop, s_disp_text5); + canvas_draw_str_aligned(canvas, 1, 52, AlignLeft, AlignTop, s_disp_text6); + } +} + +static int flipbip_scene_1_model_init( + FlipBipScene1Model* const model, + const int strength, + const uint32_t coin, + const bool overwrite, + const char* passphrase_text) { + model->page = PAGE_LOADING; + model->mnemonic_only = false; + model->strength = strength; + model->coin = coin; + model->overwrite = overwrite; + + // Allocate memory for mnemonic + char* mnemonic = malloc(TEXT_BUFFER_SIZE); + memzero(mnemonic, TEXT_BUFFER_SIZE); + + // Check if the mnemonic key & data is already saved in persistent storage, or overwrite is true + if(overwrite || (!flipbip_has_file(FlipBipFileKey, NULL, false) && + !flipbip_has_file(FlipBipFileDat, NULL, false))) { + // Set mnemonic only mode + model->mnemonic_only = true; + // Generate a random mnemonic using trezor-crypto + const char* mnemonic_gen = mnemonic_generate(strength); + // Check if the mnemonic is valid + if(mnemonic_check(mnemonic_gen) == 0) + return FlipBipStatusMnemonicCheckError; // 13 = mnemonic check error + // Save the mnemonic to persistent storage + else if(!flipbip_save_file_secure(mnemonic_gen)) + return FlipBipStatusSaveError; // 12 = save error + // Clear the generated mnemonic from memory + mnemonic_clear(); + } + + // Load the mnemonic from persistent storage + if(!flipbip_load_file_secure(mnemonic)) { + // Set mnemonic only mode for this error for memory cleanup purposes + model->mnemonic_only = true; + return FlipBipStatusLoadError; // 11 = load error + } + model->mnemonic = mnemonic; + // Check if the mnemonic is valid + if(mnemonic_check(model->mnemonic) == 0) { + // Set mnemonic only mode for this error for memory cleanup purposes + model->mnemonic_only = true; + return FlipBipStatusMnemonicCheckError; // 13 = mnemonic check error + } + + // test return values + //model->mnemonic_only = true; + //return FlipBipStatusMnemonicCheckError; // 13 = mnemonic check error + + // if we are only generating the mnemonic, return + if(model->mnemonic_only) { + return FlipBipStatusReturn; // 10 = mnemonic only, return from parent + } + + // Generate a BIP39 seed from the mnemonic + mnemonic_to_seed(model->mnemonic, passphrase_text, model->seed, 0); + + // Generate a BIP32 root HD node from the mnemonic + HDNode* root = malloc(sizeof(HDNode)); + hdnode_from_seed(model->seed, 64, SECP256K1_NAME, root); + + // buffer for key serialization + const size_t buflen = 128; + char buf[128 + 1] = {0}; + + // coin info + // bip44_coin, xprv_version, xpub_version, addr_version, wif_version, addr_format + uint32_t coin_info[6] = {0}; + for(size_t i = 0; i < 6; i++) { + coin_info[i] = COIN_INFO_ARRAY[coin][i]; + } + + // root + uint32_t fingerprint = 0; + hdnode_serialize_private(root, fingerprint, coin_info[1], buf, buflen); + char* xprv_root = malloc(buflen + 1); + strncpy(xprv_root, buf, buflen); + model->xprv_root = xprv_root; + + HDNode* node = root; + + // purpose m/44' + fingerprint = hdnode_fingerprint(node); + hdnode_private_ckd_prime(node, DERIV_PURPOSE); // purpose + + // coin m/44'/0' or m/44'/60' + fingerprint = hdnode_fingerprint(node); + hdnode_private_ckd_prime(node, coin_info[0]); // coin + + // account m/44'/0'/0' or m/44'/60'/0' + fingerprint = hdnode_fingerprint(node); + hdnode_private_ckd_prime(node, DERIV_ACCOUNT); // account + + hdnode_serialize_private(node, fingerprint, coin_info[1], buf, buflen); + char* xprv_acc = malloc(buflen + 1); + strncpy(xprv_acc, buf, buflen); + model->xprv_account = xprv_acc; + + hdnode_serialize_public(node, fingerprint, coin_info[2], buf, buflen); + char* xpub_acc = malloc(buflen + 1); + strncpy(xpub_acc, buf, buflen); + model->xpub_account = xpub_acc; + + // external/internal (change) m/44'/0'/0'/0 or m/44'/60'/0'/0 + fingerprint = hdnode_fingerprint(node); + hdnode_private_ckd(node, DERIV_CHANGE); // external/internal (change) + + hdnode_serialize_private(node, fingerprint, coin_info[1], buf, buflen); + char* xprv_ext = malloc(buflen + 1); + strncpy(xprv_ext, buf, buflen); + model->xprv_extended = xprv_ext; + + hdnode_serialize_public(node, fingerprint, coin_info[2], buf, buflen); + char* xpub_ext = malloc(buflen + 1); + strncpy(xpub_ext, buf, buflen); + model->xpub_extended = xpub_ext; + + model->node = node; + + // Initialize addresses + for(uint8_t a = 0; a < NUM_ADDRS; a++) { + model->recv_addresses[a] = malloc(MAX_ADDR_LEN); + memzero(model->recv_addresses[a], MAX_ADDR_LEN); + flipbip_scene_1_init_address(model->recv_addresses[a], node, coin, a); + + // Save QR code file + memzero(buf, buflen); + strcpy(buf, COIN_TEXT_ARRAY[coin][0]); + const unsigned char addr_num[1] = {a}; + flipbip_btox(addr_num, 1, buf + strlen(buf)); + strcpy(buf + strlen(buf), TEXT_QRFILE_EXT); + flipbip_save_qrfile(COIN_TEXT_ARRAY[coin][2], model->recv_addresses[a], buf); + memzero(buf, buflen); + } + + model->page = PAGE_INFO; + +#if USE_BIP39_CACHE + // Clear the BIP39 cache + bip39_cache_clear(); +#endif + + // 0 = success + return FlipBipStatusSuccess; +} + +bool flipbip_scene_1_input(InputEvent* event, void* context) { + furi_assert(context); + FlipBipScene1* instance = context; + + // Ignore input if busy + // if(s_busy) { + // return false; + // } + + if(event->type == InputTypeRelease) { + switch(event->key) { + case InputKeyBack: + with_view_model( + instance->view, + FlipBipScene1Model * model, + { + UNUSED(model); + instance->callback(FlipBipCustomEventScene1Back, instance->context); + }, + true); + break; + case InputKeyRight: + case InputKeyDown: + with_view_model( + instance->view, + FlipBipScene1Model * model, + { + //UNUSED(model); + int page = (model->page + 1) % (PAGE_ADDR_END + 1); + if(page == 0) { + page = PAGE_INFO; + } + model->page = page; + }, + true); + break; + case InputKeyLeft: + case InputKeyUp: + with_view_model( + instance->view, + FlipBipScene1Model * model, + { + //UNUSED(model); + int page = (model->page - 1) % (PAGE_ADDR_END + 1); + if(page == 0) { + page = PAGE_ADDR_END; + } + model->page = page; + }, + true); + break; + // case InputKeyRight: + case InputKeyOk: + // with_view_model( + // instance->view, + // FlipBipScene1Model * model, + // { + // if(model->page >= PAGE_ADDR_BEGIN && model->page <= PAGE_ADDR_END) { + + // } + // }, + // true); + // break; + // case InputKeyLeft: + case InputKeyMAX: + break; + } + } + return true; +} + +void flipbip_scene_1_exit(void* context) { + furi_assert(context); + FlipBipScene1* instance = (FlipBipScene1*)context; + + with_view_model( + instance->view, + FlipBipScene1Model * model, + { + model->page = PAGE_LOADING; + model->strength = FlipBipStrength256; + model->coin = FlipBipCoinBTC0; + memzero(model->seed, 64); + // if mnemonic_only is true, then we don't need to free the data here + if(!model->mnemonic_only) { + memzero((void*)model->mnemonic, strlen(model->mnemonic)); + free((void*)model->mnemonic); + memzero((void*)model->node, sizeof(HDNode)); + free((void*)model->node); + memzero((void*)model->xprv_root, strlen(model->xprv_root)); + memzero((void*)model->xprv_account, strlen(model->xprv_account)); + memzero((void*)model->xpub_account, strlen(model->xpub_account)); + memzero((void*)model->xprv_extended, strlen(model->xprv_extended)); + memzero((void*)model->xpub_extended, strlen(model->xpub_extended)); + free((void*)model->xprv_root); + free((void*)model->xprv_account); + free((void*)model->xpub_account); + free((void*)model->xprv_extended); + free((void*)model->xpub_extended); + for(int a = 0; a < NUM_ADDRS; a++) { + memzero((void*)model->recv_addresses[a], MAX_ADDR_LEN); + free((void*)model->recv_addresses[a]); + } + } + }, + true); + + flipbip_scene_1_clear_text(); +} + +void flipbip_scene_1_enter(void* context) { + furi_assert(context); + FlipBipScene1* instance = (FlipBipScene1*)context; + + FlipBip* app = instance->context; + + // BIP39 Strength setting + int strength = 256; // FlipBipStrength256 // 24 words (256 bit) + if(app->bip39_strength == FlipBipStrength128) { + strength = 128; // 12 words (128 bit) + } else if(app->bip39_strength == FlipBipStrength192) { + strength = 192; // 18 words (192 bit) + } + + // BIP39 Passphrase setting + const char* passphrase_text = ""; + if(app->passphrase == FlipBipPassphraseOn && strlen(app->passphrase_text) > 0) { + passphrase_text = app->passphrase_text; + } + + // BIP44 Coin setting + const uint32_t coin = app->bip44_coin; + // coin_name, derivation_path + s_derivation_text = COIN_TEXT_ARRAY[coin][1]; + + // Overwrite the saved seed with a new one setting + bool overwrite = app->overwrite_saved_seed != 0; + if(overwrite) { + s_derivation_text = TEXT_NEW_WALLET; + } + + flipbip_play_happy_bump(app); + //notification_message(app->notification, &sequence_blink_cyan_100); + flipbip_led_set_rgb(app, 255, 0, 0); + + with_view_model( + instance->view, + FlipBipScene1Model * model, + { + // s_busy = true; + + const int status = + flipbip_scene_1_model_init(model, strength, coin, overwrite, passphrase_text); + + // nonzero status, free the mnemonic + if(status != FlipBipStatusSuccess) { + memzero((void*)model->mnemonic, strlen(model->mnemonic)); + free((void*)model->mnemonic); + } + + // if error, set the error message + if(status == FlipBipStatusSaveError) { + model->mnemonic = "ERROR:,Save error"; + model->page = PAGE_MNEMONIC; + flipbip_play_long_bump(app); + } else if(status == FlipBipStatusLoadError) { + model->mnemonic = "ERROR:,Load error"; + model->page = PAGE_MNEMONIC; + flipbip_play_long_bump(app); + } else if(status == FlipBipStatusMnemonicCheckError) { + model->mnemonic = "ERROR:,Mnemonic check error"; + model->page = PAGE_MNEMONIC; + flipbip_play_long_bump(app); + } + + // s_busy = false; + + // if overwrite is set and mnemonic generated, return from scene immediately + if(status == FlipBipStatusReturn) { + instance->callback(FlipBipCustomEventScene1Back, instance->context); + } + }, + true); +} + +FlipBipScene1* flipbip_scene_1_alloc() { + FlipBipScene1* instance = malloc(sizeof(FlipBipScene1)); + instance->view = view_alloc(); + view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(FlipBipScene1Model)); + view_set_context(instance->view, instance); // furi_assert crashes in events without this + view_set_draw_callback(instance->view, (ViewDrawCallback)flipbip_scene_1_draw); + view_set_input_callback(instance->view, flipbip_scene_1_input); + view_set_enter_callback(instance->view, flipbip_scene_1_enter); + view_set_exit_callback(instance->view, flipbip_scene_1_exit); + + // allocate the address node + s_addr_node = (HDNode*)malloc(sizeof(HDNode)); + + // allocate the display text + s_disp_text1 = (char*)malloc(30 + 1); + s_disp_text2 = (char*)malloc(30 + 1); + s_disp_text3 = (char*)malloc(30 + 1); + s_disp_text4 = (char*)malloc(30 + 1); + s_disp_text5 = (char*)malloc(30 + 1); + s_disp_text6 = (char*)malloc(30 + 1); + + return instance; +} + +void flipbip_scene_1_free(FlipBipScene1* instance) { + furi_assert(instance); + + with_view_model( + instance->view, FlipBipScene1Model * model, { UNUSED(model); }, true); + + // free the address node + memzero(s_addr_node, sizeof(HDNode)); + free(s_addr_node); + + // free the display text + flipbip_scene_1_clear_text(); + free(s_disp_text1); + free(s_disp_text2); + free(s_disp_text3); + free(s_disp_text4); + free(s_disp_text5); + free(s_disp_text6); + + view_free(instance->view); + free(instance); +} + +View* flipbip_scene_1_get_view(FlipBipScene1* instance) { + furi_assert(instance); + return instance->view; +} diff --git a/applications/external/flipbip/views/flipbip_scene_1.h b/applications/external/flipbip/views/flipbip_scene_1.h new file mode 100644 index 000000000..6e370633e --- /dev/null +++ b/applications/external/flipbip/views/flipbip_scene_1.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include "../helpers/flipbip_custom_event.h" + +typedef struct FlipBipScene1 FlipBipScene1; + +typedef void (*FlipBipScene1Callback)(FlipBipCustomEvent event, void* context); + +void flipbip_scene_1_set_callback( + FlipBipScene1* flipbip_scene_1, + FlipBipScene1Callback callback, + void* context); + +View* flipbip_scene_1_get_view(FlipBipScene1* flipbip_static); + +FlipBipScene1* flipbip_scene_1_alloc(); + +void flipbip_scene_1_free(FlipBipScene1* flipbip_static); \ No newline at end of file diff --git a/applications/external/flipbip/views/flipbip_startscreen.c b/applications/external/flipbip/views/flipbip_startscreen.c new file mode 100644 index 000000000..76b060e95 --- /dev/null +++ b/applications/external/flipbip/views/flipbip_startscreen.c @@ -0,0 +1,130 @@ +#include "../flipbip.h" +#include +#include +#include +#include +#include "flipbip_icons.h" + +struct FlipBipStartscreen { + View* view; + FlipBipStartscreenCallback callback; + void* context; +}; + +typedef struct { + int some_value; +} FlipBipStartscreenModel; + +void flipbip_startscreen_set_callback( + FlipBipStartscreen* instance, + FlipBipStartscreenCallback callback, + void* context) { + furi_assert(instance); + furi_assert(callback); + instance->callback = callback; + instance->context = context; +} + +void flipbip_startscreen_draw(Canvas* canvas, FlipBipStartscreenModel* model) { + UNUSED(model); + canvas_clear(canvas); + canvas_set_color(canvas, ColorBlack); + + canvas_draw_icon(canvas, 1, 33, &I_Auth_62x31); + + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, 18, 11, "FlipBIP - BIP32/39/44"); + + canvas_set_font(canvas, FontSecondary); + canvas_draw_str(canvas, 23, 22, "Crypto toolkit for Flipper"); + canvas_draw_str(canvas, 99, 34, FLIPBIP_VERSION); + + elements_button_right(canvas, "Start"); +} + +static void flipbip_startscreen_model_init(FlipBipStartscreenModel* const model) { + model->some_value = 1; +} + +bool flipbip_startscreen_input(InputEvent* event, void* context) { + furi_assert(context); + FlipBipStartscreen* instance = context; + if(event->type == InputTypeRelease) { + switch(event->key) { + case InputKeyBack: + with_view_model( + instance->view, + FlipBipStartscreenModel * model, + { + UNUSED(model); + instance->callback(FlipBipCustomEventStartscreenBack, instance->context); + }, + true); + break; + case InputKeyLeft: + case InputKeyRight: + case InputKeyUp: + case InputKeyDown: + case InputKeyOk: + with_view_model( + instance->view, + FlipBipStartscreenModel * model, + { + UNUSED(model); + instance->callback(FlipBipCustomEventStartscreenOk, instance->context); + }, + true); + break; + case InputKeyMAX: + break; + } + } + return true; +} + +void flipbip_startscreen_exit(void* context) { + furi_assert(context); +} + +void flipbip_startscreen_enter(void* context) { + furi_assert(context); + FlipBipStartscreen* instance = (FlipBipStartscreen*)context; + with_view_model( + instance->view, + FlipBipStartscreenModel * model, + { flipbip_startscreen_model_init(model); }, + true); +} + +FlipBipStartscreen* flipbip_startscreen_alloc() { + FlipBipStartscreen* instance = malloc(sizeof(FlipBipStartscreen)); + instance->view = view_alloc(); + view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(FlipBipStartscreenModel)); + view_set_context(instance->view, instance); // furi_assert crashes in events without this + view_set_draw_callback(instance->view, (ViewDrawCallback)flipbip_startscreen_draw); + view_set_input_callback(instance->view, flipbip_startscreen_input); + //view_set_enter_callback(instance->view, flipbip_startscreen_enter); + //view_set_exit_callback(instance->view, flipbip_startscreen_exit); + + with_view_model( + instance->view, + FlipBipStartscreenModel * model, + { flipbip_startscreen_model_init(model); }, + true); + + return instance; +} + +void flipbip_startscreen_free(FlipBipStartscreen* instance) { + furi_assert(instance); + + with_view_model( + instance->view, FlipBipStartscreenModel * model, { UNUSED(model); }, true); + view_free(instance->view); + free(instance); +} + +View* flipbip_startscreen_get_view(FlipBipStartscreen* instance) { + furi_assert(instance); + return instance->view; +} diff --git a/applications/external/flipbip/views/flipbip_startscreen.h b/applications/external/flipbip/views/flipbip_startscreen.h new file mode 100644 index 000000000..d6eb1fad8 --- /dev/null +++ b/applications/external/flipbip/views/flipbip_startscreen.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include "../helpers/flipbip_custom_event.h" + +typedef struct FlipBipStartscreen FlipBipStartscreen; + +typedef void (*FlipBipStartscreenCallback)(FlipBipCustomEvent event, void* context); + +void flipbip_startscreen_set_callback( + FlipBipStartscreen* flipbip_startscreen, + FlipBipStartscreenCallback callback, + void* context); + +View* flipbip_startscreen_get_view(FlipBipStartscreen* flipbip_static); + +FlipBipStartscreen* flipbip_startscreen_alloc(); + +void flipbip_startscreen_free(FlipBipStartscreen* flipbip_static); \ No newline at end of file