Bladeren bron

Add flipbip from https://github.com/xMasterX/all-the-plugins

git-subtree-dir: flipbip
git-subtree-mainline: f6c5e154c84fc068f2547db030fde74840d29c71
git-subtree-split: 4ed4e31f7872d18aa94335a41c2bb2f12d6654a0
Willy-JL 2 jaren geleden
bovenliggende
commit
dafe1fd7be
100 gewijzigde bestanden met toevoegingen van 20410 en 0 verwijderingen
  1. 52 0
      flipbip/.gitignore
  2. 1 0
      flipbip/.gitsubtree
  3. 21 0
      flipbip/LICENSE
  4. 58 0
      flipbip/README.md
  5. 22 0
      flipbip/application.fam
  6. 234 0
      flipbip/flipbip.c
  7. 107 0
      flipbip/flipbip.h
  8. BIN
      flipbip/flipbip_10px.png
  9. 10 0
      flipbip/helpers/flipbip_custom_event.h
  10. 314 0
      flipbip/helpers/flipbip_file.c
  11. 28 0
      flipbip/helpers/flipbip_file.h
  12. 129 0
      flipbip/helpers/flipbip_string.c
  13. 12 0
      flipbip/helpers/flipbip_string.h
  14. BIN
      flipbip/icons/Auth_62x31.png
  15. BIN
      flipbip/icons/ButtonCenter_7x7.png
  16. BIN
      flipbip/icons/ButtonDown_10x5.png
  17. BIN
      flipbip/icons/ButtonLeftSmall_3x5.png
  18. BIN
      flipbip/icons/ButtonLeft_4x7.png
  19. BIN
      flipbip/icons/ButtonRightSmall_3x5.png
  20. BIN
      flipbip/icons/ButtonRight_4x7.png
  21. BIN
      flipbip/icons/ButtonUp_10x5.png
  22. BIN
      flipbip/icons/Keychain_39x36.png
  23. BIN
      flipbip/img/1.png
  24. BIN
      flipbip/img/2.png
  25. BIN
      flipbip/img/3.png
  26. 2 0
      flipbip/lib/crypto/AUTHORS
  27. 17 0
      flipbip/lib/crypto/CONTRIBUTORS
  28. 22 0
      flipbip/lib/crypto/LICENSE
  29. 187 0
      flipbip/lib/crypto/Makefile
  30. 54 0
      flipbip/lib/crypto/README.md
  31. 90 0
      flipbip/lib/crypto/address.c
  32. 39 0
      flipbip/lib/crypto/address.h
  33. 256 0
      flipbip/lib/crypto/aes/aes.h
  34. 932 0
      flipbip/lib/crypto/aes/aes_modes.c
  35. 349 0
      flipbip/lib/crypto/aes/aescrypt.c
  36. 662 0
      flipbip/lib/crypto/aes/aeskey.c
  37. 793 0
      flipbip/lib/crypto/aes/aesopt.h
  38. 403 0
      flipbip/lib/crypto/aes/aestab.c
  39. 173 0
      flipbip/lib/crypto/aes/aestab.h
  40. 189 0
      flipbip/lib/crypto/aes/aestst.c
  41. 85 0
      flipbip/lib/crypto/aes/aestst.h
  42. 241 0
      flipbip/lib/crypto/base32.c
  43. 42 0
      flipbip/lib/crypto/base32.h
  44. 219 0
      flipbip/lib/crypto/base58.c
  45. 48 0
      flipbip/lib/crypto/base58.h
  46. 1834 0
      flipbip/lib/crypto/bignum.c
  47. 195 0
      flipbip/lib/crypto/bignum.h
  48. 887 0
      flipbip/lib/crypto/bip32.c
  49. 202 0
      flipbip/lib/crypto/bip32.h
  50. 288 0
      flipbip/lib/crypto/bip39.c
  51. 61 0
      flipbip/lib/crypto/bip39.h
  52. 283 0
      flipbip/lib/crypto/bip39_english.c
  53. 222 0
      flipbip/lib/crypto/blake256.c
  54. 53 0
      flipbip/lib/crypto/blake256.h
  55. 46 0
      flipbip/lib/crypto/blake2_common.h
  56. 313 0
      flipbip/lib/crypto/blake2b.c
  57. 49 0
      flipbip/lib/crypto/blake2b.h
  58. 310 0
      flipbip/lib/crypto/blake2s.c
  59. 49 0
      flipbip/lib/crypto/blake2s.h
  60. 57 0
      flipbip/lib/crypto/byte_order.h
  61. 307 0
      flipbip/lib/crypto/cardano.c
  62. 60 0
      flipbip/lib/crypto/cardano.h
  63. 188 0
      flipbip/lib/crypto/cash_addr.c
  64. 74 0
      flipbip/lib/crypto/cash_addr.h
  65. 21 0
      flipbip/lib/crypto/chacha20poly1305/LICENSE
  66. 63 0
      flipbip/lib/crypto/chacha20poly1305/chacha20poly1305.c
  67. 22 0
      flipbip/lib/crypto/chacha20poly1305/chacha20poly1305.h
  68. 251 0
      flipbip/lib/crypto/chacha20poly1305/chacha_merged.c
  69. 316 0
      flipbip/lib/crypto/chacha20poly1305/ecrypt_config.h
  70. 49 0
      flipbip/lib/crypto/chacha20poly1305/ecrypt_machine.h
  71. 246 0
      flipbip/lib/crypto/chacha20poly1305/ecrypt_portable.h
  72. 282 0
      flipbip/lib/crypto/chacha20poly1305/ecrypt_sync.h
  73. 53 0
      flipbip/lib/crypto/chacha20poly1305/ecrypt_types.h
  74. 208 0
      flipbip/lib/crypto/chacha20poly1305/poly1305_donna.c
  75. 23 0
      flipbip/lib/crypto/chacha20poly1305/poly1305_donna.h
  76. 252 0
      flipbip/lib/crypto/chacha20poly1305/poly1305_donna_32.h
  77. 46 0
      flipbip/lib/crypto/chacha20poly1305/rfc7539.c
  78. 10 0
      flipbip/lib/crypto/chacha20poly1305/rfc7539.h
  79. 131 0
      flipbip/lib/crypto/chacha_drbg.c
  80. 59 0
      flipbip/lib/crypto/chacha_drbg.h
  81. 34 0
      flipbip/lib/crypto/check_mem.h
  82. 39 0
      flipbip/lib/crypto/curves.c
  83. 42 0
      flipbip/lib/crypto/curves.h
  84. 1284 0
      flipbip/lib/crypto/ecdsa.c
  85. 167 0
      flipbip/lib/crypto/ecdsa.h
  86. 183 0
      flipbip/lib/crypto/ed25519_donna/README.md
  87. 953 0
      flipbip/lib/crypto/ed25519_donna/curve25519_donna_32bit.c
  88. 79 0
      flipbip/lib/crypto/ed25519_donna/curve25519_donna_32bit.h
  89. 66 0
      flipbip/lib/crypto/ed25519_donna/curve25519_donna_helpers.c
  90. 22 0
      flipbip/lib/crypto/ed25519_donna/curve25519_donna_helpers.h
  91. 70 0
      flipbip/lib/crypto/ed25519_donna/curve25519_donna_scalarmult_base.c
  92. 11 0
      flipbip/lib/crypto/ed25519_donna/curve25519_donna_scalarmult_base.h
  93. 336 0
      flipbip/lib/crypto/ed25519_donna/ed25519.c
  94. 78 0
      flipbip/lib/crypto/ed25519_donna/ed25519.h
  95. 52 0
      flipbip/lib/crypto/ed25519_donna/ed25519_donna.h
  96. 1049 0
      flipbip/lib/crypto/ed25519_donna/ed25519_donna_32bit_tables.c
  97. 17 0
      flipbip/lib/crypto/ed25519_donna/ed25519_donna_32bit_tables.h
  98. 1796 0
      flipbip/lib/crypto/ed25519_donna/ed25519_donna_basepoint_table.c
  99. 2 0
      flipbip/lib/crypto/ed25519_donna/ed25519_donna_basepoint_table.h
  100. 829 0
      flipbip/lib/crypto/ed25519_donna/ed25519_donna_impl_base.c

+ 52 - 0
flipbip/.gitignore

@@ -0,0 +1,52 @@
+# Prerequisites
+*.d
+
+# Object files
+*.o
+*.ko
+*.obj
+*.elf
+
+# Linker output
+*.ilk
+*.map
+*.exp
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Libraries
+*.lib
+*.a
+*.la
+*.lo
+
+# Shared objects (inc. Windows DLLs)
+*.dll
+*.so
+*.so.*
+*.dylib
+
+# Executables
+*.exe
+*.out
+*.app
+*.i*86
+*.x86_64
+*.hex
+
+# Debug files
+*.dSYM/
+*.su
+*.idb
+*.pdb
+
+# Kernel Module Compile Results
+*.mod*
+*.cmd
+.tmp_versions/
+modules.order
+Module.symvers
+Mkfile.old
+dkms.conf

+ 1 - 0
flipbip/.gitsubtree

@@ -0,0 +1 @@
+https://github.com/xMasterX/all-the-plugins dev non_catalog_apps/FlipBIP

+ 21 - 0
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.

+ 58 - 0
flipbip/README.md

@@ -0,0 +1,58 @@
+# FlipBIP - BIP32/39/44
+
+https://github.com/xtruan/FlipBIP
+
+## Crypto toolkit for Flipper Zero
+- Using Trezor crypto libs from `core/v2.5.3` release
+
+## Background
+
+The goal of this project is to see how much crypto functionality can be brought to the Flipper Zero.
+
+### Complete
+
+- Trezor crypto C code ported into `crypto` subfolder
+  - Adapted to use Flipper hardware RNG (see `crypto/rand.c`)
+  - Imports and some C library functions modified for compatibility with FBT
+- Navigation and UI adapted from FAP Boilerplate app
+- BIP39 mnemonic generation
+  - 24, 18, or 12 words configured in settings
+- BIP39 mnemonic to BIP39 seed generation
+- Hierarchical Deterministic (HD) wallet generation from seed
+  - Generation of offline `m/44'/0'/0'/0` BTC wallet
+  - Generation of offline `m/44'/60'/0'/0` ETH wallet (coded from the $SPORK Castle of ETHDenver 2023!)
+  - Generation of offline `m/44'/3'/0'/0` DOGE wallet
+  - Generation of offline `m/44'/133'/0'/0` ZEC transparent address wallet (by @wh00hw)
+  - Similar features to: https://iancoleman.io/bip39/
+- Saving wallets to SD card
+  - Wallets are saved to SD card upon creation in `apps_data/flipbip`
+      - NOTE: `apps_data` folder must already exist on SD card!
+  - Saved wallets can be viewed between app runs
+  - Wallets are encrypted with a randomly generated key, and that key is also encrypted
+      - `.flipbip.dat` and `.flipbip.key` files are both required to be in `apps_data/flipbip`
+      - Backups of both these files `.flipbip.dat.bak` and `.flipbip.key.bak` are also maintained
+      - If you want to externally back up your wallet, I recommend copying all these files, and storing the `key` and `dat` files seperately
+  - NOTE: The wallets should be decently tough to crack off of a Flipper, however any Flipper with the app installed can load a wallet in the `apps_data/flipbip` directory if both the `key` and `dat` file are present
+- BIP39 passphrase support
+  - Configured in settings, not persisted between runs for security
+- Import your own mnemonic
+  - Lots of typing required but you can now use the wallet with an existing mnemonic you have saved
+  - Useful to convert paper backup to keys and receive addresses without relying on a laptop or phone
+- Improved receive address generation features
+  - Addresses are now generated at the same time as other pieces of wallet info
+    - This slows down initial wallet load, but makes UI much more responsive
+  - QR code files are now generated for each address and stored in the `apps_data/flipbip` directory
+    - This app is required to view the QR code files: https://github.com/bmatcuk/flipperzero-qrcode
+    - NOTE: This happens during the `View Wallet` step; you must view a wallet after generating/importing a wallet in order to ensure the address QR files are correct
+- Broke out crypto functionality into its own library using `fap_private_libs` feature
+
+### Work in Progress
+
+- More coin types
+  - Support for more custom BIP32 wallet paths
+
+### (FAR) Future
+
+- Custom wallet security
+  - User specified password
+- USB/Bluetooth wallet functionality

+ 22 - 0
flipbip/application.fam

@@ -0,0 +1,22 @@
+App(
+    appid="flipbip",
+    name="FlipBIP Crypto Wallet",
+    apptype=FlipperAppType.EXTERNAL,
+    entry_point="flipbip_app",
+    requires=[
+        "gui",
+    ],
+    stack_size=3 * 1024,
+    order=10,
+    fap_icon="flipbip_10px.png",
+    fap_private_libs=[
+        Lib(
+            name="crypto",
+        ),
+    ],
+    fap_category="Tools",
+    fap_author="Struan Clark (xtruan)",
+    fap_weburl="https://github.com/xtruan/FlipBIP",
+    fap_version=(1, 14),
+    fap_description="Crypto wallet for Flipper",
+)

+ 234 - 0
flipbip/flipbip.c

@@ -0,0 +1,234 @@
+#include "flipbip.h"
+#include "helpers/flipbip_file.h"
+// From: lib/crypto
+#include <memzero.h>
+#include <bip39.h>
+
+#define MNEMONIC_MENU_DEFAULT "Import mnemonic seed"
+#define MNEMONIC_MENU_SUCCESS "Import seed (success)"
+#define MNEMONIC_MENU_FAILURE "Import seed (failed!)"
+
+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;
+            // switch back to settings view
+            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) {
+                    app->mnemonic_menu_text = MNEMONIC_MENU_SUCCESS;
+                    //notification_message(app->notification, &sequence_blink_cyan_100);
+                    //flipbip_play_happy_bump(app);
+                } else {
+                    app->mnemonic_menu_text = MNEMONIC_MENU_FAILURE;
+                    //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;
+            // exit scene 1 instance that's being used for text input and go back to menu
+            scene_manager_previous_scene(app->scene_manager);
+            //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;
+        // something went wrong, switch to menu view
+        view_dispatcher_switch_to_view(app->view_dispatcher, FlipBipViewIdMenu);
+    }
+}
+
+static void flipbip_scene_renew_dialog_callback(DialogExResult result, void* context) {
+    FlipBip* app = context;
+    if(result == DialogExResultRight) {
+        app->wallet_create(app);
+    } else {
+        view_dispatcher_switch_to_view(app->view_dispatcher, FlipBipViewIdMenu);
+    }
+}
+
+static void flipbip_wallet_create(void* context) {
+    FlipBip* app = context;
+    furi_assert(app);
+    scene_manager_set_scene_state(
+        app->scene_manager, FlipBipSceneMenu, SubmenuIndexScene1New);
+    scene_manager_next_scene(app->scene_manager, FlipBipSceneScene_1);
+}
+
+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->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;
+    app->mnemonic_menu_text = MNEMONIC_MENU_DEFAULT;
+
+    // Text input
+    app->input_state = FlipBipTextInputDefault;
+
+    view_dispatcher_add_view(
+        app->view_dispatcher, FlipBipViewIdMenu, submenu_get_view(app->submenu));
+    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));
+
+    app->wallet_create = flipbip_wallet_create;
+    app->renew_dialog = dialog_ex_alloc();
+    dialog_ex_set_result_callback(app->renew_dialog, flipbip_scene_renew_dialog_callback);
+    dialog_ex_set_context(app->renew_dialog, app);
+    dialog_ex_set_left_button_text(app->renew_dialog, "No");
+    dialog_ex_set_right_button_text(app->renew_dialog, "Yes");
+    dialog_ex_set_header(app->renew_dialog, "Current wallet\nWill be lost.\nProceed?", 16, 12, AlignLeft, AlignTop);
+    view_dispatcher_add_view(
+        app->view_dispatcher, FlipBipViewRenewConfirm, dialog_ex_get_view(app->renew_dialog));
+
+    // 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_remove_view(app->view_dispatcher, FlipBipViewRenewConfirm);
+    dialog_ex_free(app->renew_dialog);
+
+    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, FlipBipSceneMenu); //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;
+}

+ 107 - 0
flipbip/flipbip.h

@@ -0,0 +1,107 @@
+#pragma once
+
+#include <furi.h>
+#include <furi_hal.h>
+#include <gui/gui.h>
+#include <input/input.h>
+#include <stdlib.h>
+//#include <notification/notification_messages.h>
+#include <gui/view_dispatcher.h>
+#include <gui/modules/submenu.h>
+#include <gui/scene_manager.h>
+#include <gui/modules/dialog_ex.h>
+#include <gui/modules/variable_item_list.h>
+#include <gui/modules/text_input.h>
+#include "scenes/flipbip_scene.h"
+#include "views/flipbip_scene_1.h"
+
+#define FLIPBIP_VERSION "v1.14"
+
+#define COIN_BTC 0
+#define COIN_DOGE 3
+#define COIN_ETH 60
+#define COIN_ZEC 133
+
+#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;
+    DialogEx* renew_dialog;
+    FlipBipScene1* flipbip_scene_1;
+    char* mnemonic_menu_text;
+    // Settings options
+    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];
+
+    void (* wallet_create)(void* context);
+} FlipBip;
+
+typedef enum {
+    FlipBipViewIdStartscreen,
+    FlipBipViewIdMenu,
+    FlipBipViewIdScene1,
+    FlipBipViewIdSettings,
+    FlipBipViewIdTextInput,
+    FlipBipViewRenewConfirm,
+} FlipBipViewId;
+
+typedef enum {
+    FlipBipStrength128,
+    FlipBipStrength192,
+    FlipBipStrength256,
+} FlipBipStrengthState;
+
+typedef enum {
+    FlipBipPassphraseOff,
+    FlipBipPassphraseOn,
+} FlipBipPassphraseState;
+
+typedef enum {
+    FlipBipCoinBTC0,
+    FlipBipCoinETH60,
+    FlipBipCoinDOGE3,
+    FlipBipCoinZEC133,
+} FlipBipCoin;
+
+typedef enum {
+    FlipBipTextInputDefault,
+    FlipBipTextInputPassphrase,
+    FlipBipTextInputMnemonic
+} FlipBipTextInputState;
+
+typedef enum {
+    FlipBipStatusSuccess = 0,
+    FlipBipStatusReturn = 10,
+    FlipBipStatusLoadError = 11,
+    FlipBipStatusSaveError = 12,
+    FlipBipStatusMnemonicCheckError = 13,
+} FlipBipStatus;
+
+typedef enum {
+    SubmenuIndexScene1BTC = 10,
+    SubmenuIndexScene1ETH,
+    SubmenuIndexScene1DOGE,
+    SubmenuIndexScene1ZEC,
+    SubmenuIndexScene1New,
+    SubmenuIndexScene1Renew,
+    SubmenuIndexScene1Import,
+    SubmenuIndexSettings,
+    SubmenuIndexNOP,
+} SubmenuIndex;

BIN
flipbip/flipbip_10px.png


+ 10 - 0
flipbip/helpers/flipbip_custom_event.h

@@ -0,0 +1,10 @@
+#pragma once
+
+typedef enum {
+    FlipBipCustomEventScene1Up,
+    FlipBipCustomEventScene1Down,
+    FlipBipCustomEventScene1Left,
+    FlipBipCustomEventScene1Right,
+    FlipBipCustomEventScene1Ok,
+    FlipBipCustomEventScene1Back,
+} FlipBipCustomEvent;

+ 314 - 0
flipbip/helpers/flipbip_file.c

@@ -0,0 +1,314 @@
+#include "flipbip_file.h"
+#include <storage/storage.h>
+#include <loader/loader.h>
+#include "../helpers/flipbip_string.h"
+// From: lib/crypto
+#include <memzero.h>
+#include <rand.h>
+
+// #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,
+    size_t slen,
+    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;
+        size_t i = 0;
+        while((storage_file_read(settings_file, &chr, 1) == 1) &&
+              !storage_file_eof(settings_file) && !isspace(chr)) {
+            if(i < slen) {
+                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, dlen, 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, dlen, 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;
+}

+ 28 - 0
flipbip/helpers/flipbip_file.h

@@ -0,0 +1,28 @@
+#include <stdbool.h>
+#include <stddef.h>
+
+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,
+    size_t slen,
+    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);

+ 129 - 0
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 <ctype.h>
+#include <stdint.h>
+#include <string.h>
+// From: lib/crypto
+#include <memzero.h>
+#include <rc4.h>
+
+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);
+}

+ 12 - 0
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);

BIN
flipbip/icons/Auth_62x31.png


BIN
flipbip/icons/ButtonCenter_7x7.png


BIN
flipbip/icons/ButtonDown_10x5.png


BIN
flipbip/icons/ButtonLeftSmall_3x5.png


BIN
flipbip/icons/ButtonLeft_4x7.png


BIN
flipbip/icons/ButtonRightSmall_3x5.png


BIN
flipbip/icons/ButtonRight_4x7.png


BIN
flipbip/icons/ButtonUp_10x5.png


BIN
flipbip/icons/Keychain_39x36.png


BIN
flipbip/img/1.png


BIN
flipbip/img/2.png


BIN
flipbip/img/3.png


+ 2 - 0
flipbip/lib/crypto/AUTHORS

@@ -0,0 +1,2 @@
+Tomas Dzetkulic <dzetkulic@gmail.com>
+Pavol Rusnak <stick@gk2.sk>

+ 17 - 0
flipbip/lib/crypto/CONTRIBUTORS

@@ -0,0 +1,17 @@
+Tomas Dzetkulic <dzetkulic@gmail.com>
+Pavol Rusnak <stick@gk2.sk>
+Jochen Hoenicke <hoenicke@gmail.com>
+Dustin Laurence <dustin@laurences.net>
+Ondrej Mikle <ondrej.mikle@nic.cz>
+Roman Zeyde <roman.zeyde@gmail.com>
+Alex Beregszaszi <alex@rtfs.hu>
+netanelkl <netanel.keidar@gmail.com>
+Jan Pochyla <jpochyla@gmail.com>
+Ondrej Mikle <ondrej.mikle@gmail.com>
+Josh Billings <jdb6167@rit.edu>
+Adam Mackler <AdamMackler@gmail.com>
+Oleg Andreev <oleganza@gmail.com>
+mog <mog@rush.rldn.net>
+John Dvorak <johndvorak26@gmail.com>
+Christian Reitter <invd@inhq.net>
+Struan Clark <xtruan@users.noreply.github.com>

+ 22 - 0
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.

+ 187 - 0
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-*

+ 54 - 0
flipbip/lib/crypto/README.md

@@ -0,0 +1,54 @@
+# trezor-crypto
+
+Heavily optimized cryptography algorithms for embedded devices.
+
+These include:
+- AES/Rijndael encryption/decryption
+- Big Number (256 bit) Arithmetics
+- BIP32 Hierarchical Deterministic Wallets
+- BIP39 Mnemonic code
+- ECDSA signing/verifying (supports secp256k1 and nist256p1 curves,
+  uses RFC6979 for deterministic signatures)
+- ECDSA public key derivation
+- BIP340 Schnorr signature signing/verifying
+- Base32 (RFC4648 and custom alphabets)
+- Base58 address representation
+- Ed25519 signing/verifying (also SHA3 and Keccak variants)
+- ECDH using secp256k1, nist256p1 and Curve25519
+- HMAC-SHA256 and HMAC-SHA512
+- PBKDF2
+- RIPEMD-160
+- SHA1
+- SHA2-256/SHA2-512
+- SHA3/Keccak
+- BLAKE2s/BLAKE2b
+- Chacha20-Poly1305
+- unit tests (using Check - check.sf.net; in test_check.c)
+- tests against OpenSSL (in test_openssl.c)
+- integrated Wycheproof tests
+
+Distibuted under MIT License.
+
+## Some parts of the library come from external sources:
+
+- AES: https://github.com/BrianGladman/aes
+- Base58: https://github.com/luke-jr/libbase58
+- BLAKE2s/BLAKE2b: https://github.com/BLAKE2/BLAKE2
+- RIPEMD-160: https://github.com/ARMmbed/mbedtls
+- SHA1/SHA2: http://www.aarongifford.com/computers/sha.html
+- SHA3: https://github.com/rhash/RHash
+- Curve25519: https://github.com/agl/curve25519-donna
+- Ed25519: https://github.com/floodyberry/ed25519-donna
+- Chacha20: https://github.com/wg/c20p1305
+- Poly1305: https://github.com/floodyberry/poly1305-donna
+
+## Repo source:
+
+```
+remote = git+ssh://git@github.com/trezor/trezor-crypto
+branch = master
+commit = 915b3dbbbf58c262865647728a3463b8785fc965
+parent = 6ad3294f31a1e7484b43c104ff2880b965198cad
+method = rebase
+cmdver = 0.4.0
+```

+ 90 - 0
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

+ 39 - 0
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 <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#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

+ 256 - 0
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 <stdlib.h>
+#include <stdint.h>
+
+#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

+ 932 - 0
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 <string.h>
+#include <assert.h>
+#include <stdint.h>
+
+#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

+ 349 - 0
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

+ 662 - 0
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

+ 793 - 0
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

+ 403 - 0
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

+ 173 - 0
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

+ 189 - 0
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 <stdio.h>
+#include <string.h>
+
+#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;
+}

+ 85 - 0
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

+ 241 - 0
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 <string.h>
+
+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;
+    }
+}

+ 42 - 0
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 <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+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

+ 219 - 0
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 <stdbool.h>
+#include <string.h>
+#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;
+}

+ 48 - 0
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 <stdbool.h>
+#include <stdint.h>
+#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

+ 1834 - 0
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 <assert.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#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

+ 195 - 0
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 <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#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

+ 887 - 0
flipbip/lib/crypto/bip32.c

@@ -0,0 +1,887 @@
+/**
+ * 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 <stdbool.h>
+#include <string.h>
+
+#include "address.h"
+#if USE_NEM
+#include "aes/aes.h"
+#endif
+#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;
+}

+ 202 - 0
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 <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#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

+ 288 - 0
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 <stdbool.h>
+#include <string.h>
+
+#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;
+}

+ 61 - 0
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 <stdbool.h>
+#include <stdint.h>
+
+#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

+ 283 - 0
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",
+};

+ 222 - 0
flipbip/lib/crypto/blake256.c

@@ -0,0 +1,222 @@
+/*
+   BLAKE reference C implementation
+
+   Copyright (c) 2012 Jean-Philippe Aumasson <jeanphilippe.aumasson@gmail.com>
+
+   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 <http://creativecommons.org/publicdomain/zero/1.0/>.
+ */
+#include "blake256.h"
+
+#include <string.h>
+
+#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);
+}

+ 53 - 0
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 <stdint.h>
+#include <stddef.h>
+
+#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__ */

+ 46 - 0
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));
+}

+ 313 - 0
flipbip/lib/crypto/blake2b.c

@@ -0,0 +1,313 @@
+/*
+   BLAKE2 reference source code package - reference C implementations
+
+   Copyright 2012, Samuel Neves <sneves@dei.uc.pt>.  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 <string.h>
+
+#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;
+}

+ 49 - 0
flipbip/lib/crypto/blake2b.h

@@ -0,0 +1,49 @@
+#ifndef __BLAKE2B_H__
+#define __BLAKE2B_H__
+
+#include <stdint.h>
+#include <stddef.h>
+
+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

+ 310 - 0
flipbip/lib/crypto/blake2s.c

@@ -0,0 +1,310 @@
+/*
+   BLAKE2 reference source code package - reference C implementations
+
+   Copyright 2012, Samuel Neves <sneves@dei.uc.pt>.  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 <string.h>
+
+#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;
+}

+ 49 - 0
flipbip/lib/crypto/blake2s.h

@@ -0,0 +1,49 @@
+#ifndef __BLAKE2S_H__
+#define __BLAKE2S_H__
+
+#include <stdint.h>
+#include <stddef.h>
+
+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

+ 57 - 0
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 <sys/types.h> (which in turn includes
+ * <machine/endian.h> 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

+ 307 - 0
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 <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+#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

+ 60 - 0
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 <stdbool.h>
+#include <stdint.h>
+#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__

+ 188 - 0
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 <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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;
+}

+ 74 - 0
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 <stdint.h>
+
+/** 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

+ 21 - 0
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.

+ 63 - 0
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);
+}

+ 22 - 0
flipbip/lib/crypto/chacha20poly1305/chacha20poly1305.h

@@ -0,0 +1,22 @@
+#ifndef CHACHA20POLY1305_H
+#define CHACHA20POLY1305_H
+
+#include <stdint.h>
+#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

+ 251 - 0
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);
+}

+ 316 - 0
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 <limits.h>
+
+/* --- 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 <xmmintrin.h>
+#define MAXT __m128
+
+#elif defined(__MMX__)
+
+#include <mmintrin.h>
+#define MAXT __m64
+
+#elif defined(__ALTIVEC__)
+
+#define MAXT __vector int
+
+#else
+
+#define MAXT long
+
+#endif
+
+/* ------------------------------------------------------------------------- */
+
+#endif

+ 49 - 0
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 <stdlib.h>
+
+#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
+
+/* ------------------------------------------------------------------------- */

+ 246 - 0
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

+ 282 - 0
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

+ 53 - 0
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

+ 208 - 0
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;
+}

+ 23 - 0
flipbip/lib/crypto/chacha20poly1305/poly1305_donna.h

@@ -0,0 +1,23 @@
+#ifndef POLY1305_DONNA_H
+#define POLY1305_DONNA_H
+
+#include <stddef.h>
+
+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 */

+ 252 - 0
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;
+}

+ 46 - 0
flipbip/lib/crypto/chacha20poly1305/rfc7539.c

@@ -0,0 +1,46 @@
+// Implementation of the ChaCha20 + Poly1305 AEAD construction
+// as described in RFC 7539.
+
+#include <string.h>
+#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);
+}

+ 10 - 0
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

+ 131 - 0
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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "chacha_drbg.h"
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+#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;
+}

+ 59 - 0
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 <http://www.gnu.org/licenses/>.
+ */
+
+#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__

+ 34 - 0
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

+ 39 - 0
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";

+ 42 - 0
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

+ 1284 - 0
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 <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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;
+}

+ 167 - 0
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 <stdint.h>
+#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

+ 183 - 0
flipbip/lib/crypto/ed25519_donna/README.md

@@ -0,0 +1,183 @@
+[ed25519](https://ed25519.cr.yp.to) is an
+[Elliptic Curve Digital Signature Algortithm](https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm),
+developed by [Dan Bernstein](https://cr.yp.to/djb.html),
+[Niels Duif](https://www.nielsduif.nl),
+[Tanja Lange](https://hyperelliptic.org/tanja),
+[Peter Schwabe](https://cryptojedi.org/peter),
+and [Bo-Yin Yang](https://www.iis.sinica.edu.tw/pages/byyang).
+
+This project provides performant, portable 32-bit & 64-bit implementations. All implementations are
+of course constant time in regard to secret data.
+
+#### Performance
+
+SSE2 code and benches have not been updated yet. I will do those next.
+
+Compilers versions are gcc 4.6.3, icc 13.1.1, clang 3.4-1~exp1.
+
+Batch verification time (in parentheses) is the average time per 1 verification in a batch of 64 signatures. Counts are in thousands of cycles.
+
+Note that SSE2 performance may be less impressive on AMD & older CPUs with slower SSE ops!
+
+Visual Studio performance for `ge25519_scalarmult_base_niels` will lag behind a bit until optimized assembler versions of `ge25519_scalarmult_base_choose_niels`
+are made.
+
+##### E5200 @ 2.5ghz, march=core2
+
+<table>
+<thead><tr><th>Implementation</th><th>Sign</th><th>gcc</th><th>icc</th><th>clang</th><th>Verify</th><th>gcc</th><th>icc</th><th>clang</th></tr></thead>
+<tbody>
+<tr><td>ed25519-donna 64bit     </td><td></td><td>100k</td><td>110k</td><td>137k</td><td></td><td>327k (144k) </td><td>342k (163k) </td><td>422k (194k) </td></tr>
+<tr><td>amd64-64-24k            </td><td></td><td>102k</td><td>    </td><td>    </td><td></td><td>355k (158k) </td><td>            </td><td>            </td></tr>
+<tr><td>ed25519-donna-sse2 64bit</td><td></td><td>108k</td><td>111k</td><td>116k</td><td></td><td>353k (155k) </td><td>345k (154k) </td><td>360k (161k) </td></tr>
+<tr><td>amd64-51-32k            </td><td></td><td>116k</td><td>    </td><td>    </td><td></td><td>380k (175k) </td><td>            </td><td>            </td></tr>
+<tr><td>ed25519-donna-sse2 32bit</td><td></td><td>147k</td><td>147k</td><td>156k</td><td></td><td>380k (178k) </td><td>381k (173k) </td><td>430k (192k) </td></tr>
+<tr><td>ed25519-donna 32bit     </td><td></td><td>597k</td><td>335k</td><td>380k</td><td></td><td>1693k (720k)</td><td>1052k (453k)</td><td>1141k (493k)</td></tr>
+</tbody>
+</table>
+
+##### E3-1270 @ 3.4ghz, march=corei7-avx
+
+<table>
+<thead><tr><th>Implementation</th><th>Sign</th><th>gcc</th><th>icc</th><th>clang</th><th>Verify</th><th>gcc</th><th>icc</th><th>clang</th></tr></thead>
+<tbody>
+<tr><td>amd64-64-24k            </td><td></td><td> 68k</td><td>    </td><td>    </td><td></td><td>225k (104k) </td><td>            </td><td>            </td></tr>
+<tr><td>ed25519-donna 64bit     </td><td></td><td> 71k</td><td> 75k</td><td> 90k</td><td></td><td>226k (105k) </td><td>226k (112k) </td><td>277k (125k) </td></tr>
+<tr><td>amd64-51-32k            </td><td></td><td> 72k</td><td>    </td><td>    </td><td></td><td>218k (107k) </td><td>            </td><td>            </td></tr>
+<tr><td>ed25519-donna-sse2 64bit</td><td></td><td> 79k</td><td> 82k</td><td> 92k</td><td></td><td>252k (122k) </td><td>259k (124k) </td><td>282k (131k) </td></tr>
+<tr><td>ed25519-donna-sse2 32bit</td><td></td><td> 94k</td><td> 95k</td><td>103k</td><td></td><td>296k (146k) </td><td>294k (137k) </td><td>306k (147k) </td></tr>
+<tr><td>ed25519-donna 32bit     </td><td></td><td>525k</td><td>299k</td><td>316k</td><td></td><td>1502k (645k)</td><td>959k (418k) </td><td>954k (416k) </td></tr>
+</tbody>
+</table>
+
+#### Compilation
+
+No configuration is needed **if you are compiling against OpenSSL**.
+
+##### Hash Options
+
+If you are not compiling aginst OpenSSL, you will need a hash function.
+
+To use a simple/**slow** implementation of SHA-512, use `-DED25519_REFHASH` when compiling `ed25519.c`.
+This should never be used except to verify the code works when OpenSSL is not available.
+
+To use a custom hash function, use `-DED25519_CUSTOMHASH` when compiling `ed25519.c` and put your
+custom hash implementation in ed25519-hash-custom.h. The 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);
+
+##### Random Options
+
+If you are not compiling aginst OpenSSL, you will need a random function for batch verification.
+
+To use a custom random function, use `-DED25519_CUSTOMRANDOM` when compiling `ed25519.c` and put your
+custom hash implementation in ed25519-randombytes-custom.h. The random function must implement:
+
+	void ED25519_FN(ed25519_randombytes_unsafe) (void *p, size_t len);
+
+Use `-DED25519_TEST` when compiling `ed25519.c` to use a deterministically seeded, non-thread safe CSPRNG
+variant of Bob Jenkins [ISAAC](https://en.wikipedia.org/wiki/ISAAC_%28cipher%29)
+
+##### Minor options
+
+Use `-DED25519_INLINE_ASM` to disable the use of custom assembler routines and instead rely on portable C.
+
+Use `-DED25519_FORCE_32BIT` to force the use of 32 bit routines even when compiling for 64 bit.
+
+##### 32-bit
+
+	gcc ed25519.c -m32 -O3 -c
+
+##### 64-bit
+
+	gcc ed25519.c -m64 -O3 -c
+
+##### SSE2
+
+	gcc ed25519.c -m32 -O3 -c -DED25519_SSE2 -msse2
+	gcc ed25519.c -m64 -O3 -c -DED25519_SSE2
+
+clang and icc are also supported
+
+
+#### Usage
+
+To use the code, link against `ed25519.o -mbits` and:
+
+	#include "ed25519.h"
+
+Add `-lssl -lcrypto` when using OpenSSL (Some systems don't need -lcrypto? It might be trial and error).
+
+To generate a private key, simply generate 32 bytes from a secure
+cryptographic source:
+
+	ed25519_secret_key sk;
+	randombytes(sk, sizeof(ed25519_secret_key));
+
+To generate a public key:
+
+	ed25519_public_key pk;
+	ed25519_publickey(sk, pk);
+
+To sign a message:
+
+	ed25519_signature sig;
+	ed25519_sign(message, message_len, sk, signature);
+
+To verify a signature:
+
+	int valid = ed25519_sign_open(message, message_len, pk, signature) == 0;
+
+To batch verify signatures:
+
+	const unsigned char *mp[num] = {message1, message2..}
+	size_t ml[num] = {message_len1, message_len2..}
+	const unsigned char *pkp[num] = {pk1, pk2..}
+	const unsigned char *sigp[num] = {signature1, signature2..}
+	int valid[num]
+
+	/* valid[i] will be set to 1 if the individual signature was valid, 0 otherwise */
+	int all_valid = ed25519_sign_open_batch(mp, ml, pkp, sigp, num, valid) == 0;
+
+**Note**: Batch verification uses `ed25519_randombytes_unsafe`, implemented in
+`ed25519-randombytes.h`, to generate random scalars for the verification code.
+The default implementation now uses OpenSSLs `RAND_bytes`.
+
+Unlike the [SUPERCOP](https://bench.cr.yp.to/supercop.html) version, signatures are
+not appended to messages, and there is no need for padding in front of messages.
+Additionally, the secret key does not contain a copy of the public key, so it is
+32 bytes instead of 64 bytes, and the public key must be provided to the signing
+function.
+
+##### Curve25519
+
+Curve25519 public keys can be generated thanks to
+[Adam Langley](https://www.imperialviolet.org/2013/05/10/fastercurve25519.html)
+leveraging Ed25519's precomputed basepoint scalar multiplication.
+
+	curved25519_key sk, pk;
+	randombytes(sk, sizeof(curved25519_key));
+	curved25519_scalarmult_basepoint(pk, sk);
+
+Note the name is curved25519, a combination of curve and ed25519, to prevent
+name clashes. Performance is slightly faster than short message ed25519
+signing due to both using the same code for the scalar multiply.
+
+#### Testing
+
+Fuzzing against reference implemenations is now available. See [fuzz/README](fuzz/README.md).
+
+Building `ed25519.c` with `-DED25519_TEST` and linking with `test.c` will run basic sanity tests
+and benchmark each function. `test-batch.c` has been incorporated in to `test.c`.
+
+`test-internals.c` is standalone and built the same way as `ed25519.c`. It tests the math primitives
+with extreme values to ensure they function correctly. SSE2 is now supported.
+
+#### Papers
+
+[Available on the Ed25519 website](https://ed25519.cr.yp.to/papers.html)

+ 953 - 0
flipbip/lib/crypto/ed25519_donna/curve25519_donna_32bit.c

@@ -0,0 +1,953 @@
+/*
+	Public domain by Andrew M. <liquidsun@gmail.com>
+	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;
+}

+ 79 - 0
flipbip/lib/crypto/ed25519_donna/curve25519_donna_32bit.h

@@ -0,0 +1,79 @@
+/*
+	Public domain by Andrew M. <liquidsun@gmail.com>
+	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]);

+ 66 - 0
flipbip/lib/crypto/ed25519_donna/curve25519_donna_helpers.c

@@ -0,0 +1,66 @@
+/*
+	Public domain by Andrew M. <liquidsun@gmail.com>
+	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);
+}

+ 22 - 0
flipbip/lib/crypto/ed25519_donna/curve25519_donna_helpers.h

@@ -0,0 +1,22 @@
+/*
+	Public domain by Andrew M. <liquidsun@gmail.com>
+	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);

+ 70 - 0
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);
+}

+ 11 - 0
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);

+ 336 - 0
flipbip/lib/crypto/ed25519_donna/ed25519.c

@@ -0,0 +1,336 @@
+/*
+	Public domain by Andrew M. <liquidsun@gmail.com>
+
+	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

+ 78 - 0
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

+ 52 - 0
flipbip/lib/crypto/ed25519_donna/ed25519_donna.h

@@ -0,0 +1,52 @@
+/*
+	Public domain by Andrew M. <liquidsun@gmail.com>
+	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

+ 1049 - 0
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}}};

+ 17 - 0
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];

+ 1796 - 0
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}};

+ 2 - 0
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];

+ 829 - 0
flipbip/lib/crypto/ed25519_donna/ed25519_donna_impl_base.c

@@ -0,0 +1,829 @@
+#include <assert.h>
+#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);
+}

Some files were not shown because too many files changed in this diff