Struan Clark 2 лет назад
Родитель
Сommit
b3236278d9
100 измененных файлов с 21042 добавлено и 0 удалено
  1. 9 0
      crypto/.gitignore
  2. 3 0
      crypto/.gitmodules
  3. 12 0
      crypto/.gitrepo
  4. 2 0
      crypto/AUTHORS
  5. 16 0
      crypto/CONTRIBUTORS
  6. 22 0
      crypto/LICENSE
  7. 187 0
      crypto/Makefile
  8. 45 0
      crypto/README.md
  9. 94 0
      crypto/address.c
  10. 40 0
      crypto/address.h
  11. 226 0
      crypto/aes/aes.h
  12. 957 0
      crypto/aes/aes_modes.c
  13. 307 0
      crypto/aes/aescrypt.c
  14. 560 0
      crypto/aes/aeskey.c
  15. 784 0
      crypto/aes/aesopt.h
  16. 418 0
      crypto/aes/aestab.c
  17. 173 0
      crypto/aes/aestab.h
  18. 182 0
      crypto/aes/aestst.c
  19. 85 0
      crypto/aes/aestst.h
  20. 241 0
      crypto/base32.c
  21. 44 0
      crypto/base32.h
  22. 221 0
      crypto/base58.c
  23. 46 0
      crypto/base58.h
  24. 1848 0
      crypto/bignum.c
  25. 175 0
      crypto/bignum.h
  26. 817 0
      crypto/bip32.c
  27. 149 0
      crypto/bip32.h
  28. 286 0
      crypto/bip39.c
  29. 60 0
      crypto/bip39.h
  30. 369 0
      crypto/bip39_english.c
  31. 234 0
      crypto/blake256.c
  32. 53 0
      crypto/blake256.h
  33. 44 0
      crypto/blake2_common.h
  34. 324 0
      crypto/blake2b.c
  35. 41 0
      crypto/blake2b.h
  36. 318 0
      crypto/blake2s.c
  37. 41 0
      crypto/blake2s.h
  38. 59 0
      crypto/byte_order.h
  39. 306 0
      crypto/cardano.c
  40. 54 0
      crypto/cardano.h
  41. 189 0
      crypto/cash_addr.c
  42. 77 0
      crypto/cash_addr.h
  43. 21 0
      crypto/chacha20poly1305/LICENSE
  44. 60 0
      crypto/chacha20poly1305/chacha20poly1305.c
  45. 19 0
      crypto/chacha20poly1305/chacha20poly1305.h
  46. 252 0
      crypto/chacha20poly1305/chacha_merged.c
  47. 316 0
      crypto/chacha20poly1305/ecrypt-config.h
  48. 49 0
      crypto/chacha20poly1305/ecrypt-machine.h
  49. 275 0
      crypto/chacha20poly1305/ecrypt-portable.h
  50. 290 0
      crypto/chacha20poly1305/ecrypt-sync.h
  51. 53 0
      crypto/chacha20poly1305/ecrypt-types.h
  52. 219 0
      crypto/chacha20poly1305/poly1305-donna-32.h
  53. 179 0
      crypto/chacha20poly1305/poly1305-donna.c
  54. 20 0
      crypto/chacha20poly1305/poly1305-donna.h
  55. 48 0
      crypto/chacha20poly1305/rfc7539.c
  56. 10 0
      crypto/chacha20poly1305/rfc7539.h
  57. 126 0
      crypto/chacha_drbg.c
  58. 54 0
      crypto/chacha_drbg.h
  59. 30 0
      crypto/check_mem.h
  60. 39 0
      crypto/curves.c
  61. 42 0
      crypto/curves.h
  62. 1251 0
      crypto/ecdsa.c
  63. 128 0
      crypto/ecdsa.h
  64. 183 0
      crypto/ed25519-donna/README.md
  65. 681 0
      crypto/ed25519-donna/curve25519-donna-32bit.c
  66. 79 0
      crypto/ed25519-donna/curve25519-donna-32bit.h
  67. 66 0
      crypto/ed25519-donna/curve25519-donna-helpers.c
  68. 22 0
      crypto/ed25519-donna/curve25519-donna-helpers.h
  69. 67 0
      crypto/ed25519-donna/curve25519-donna-scalarmult-base.c
  70. 8 0
      crypto/ed25519-donna/curve25519-donna-scalarmult-base.h
  71. 63 0
      crypto/ed25519-donna/ed25519-donna-32bit-tables.c
  72. 17 0
      crypto/ed25519-donna/ed25519-donna-32bit-tables.h
  73. 261 0
      crypto/ed25519-donna/ed25519-donna-basepoint-table.c
  74. 2 0
      crypto/ed25519-donna/ed25519-donna-basepoint-table.h
  75. 730 0
      crypto/ed25519-donna/ed25519-donna-impl-base.c
  76. 104 0
      crypto/ed25519-donna/ed25519-donna-impl-base.h
  77. 24 0
      crypto/ed25519-donna/ed25519-donna-portable.h
  78. 52 0
      crypto/ed25519-donna/ed25519-donna.h
  79. 23 0
      crypto/ed25519-donna/ed25519-hash-custom-keccak.h
  80. 23 0
      crypto/ed25519-donna/ed25519-hash-custom-sha3.h
  81. 23 0
      crypto/ed25519-donna/ed25519-hash-custom.h
  82. 8 0
      crypto/ed25519-donna/ed25519-keccak.c
  83. 21 0
      crypto/ed25519-donna/ed25519-keccak.h
  84. 8 0
      crypto/ed25519-donna/ed25519-sha3.c
  85. 21 0
      crypto/ed25519-donna/ed25519-sha3.h
  86. 318 0
      crypto/ed25519-donna/ed25519.c
  87. 45 0
      crypto/ed25519-donna/ed25519.h
  88. 517 0
      crypto/ed25519-donna/modm-donna-32bit.c
  89. 80 0
      crypto/ed25519-donna/modm-donna-32bit.h
  90. 105 0
      crypto/fuzzer/README.md
  91. 399 0
      crypto/fuzzer/extract_fuzzer_dictionary.py
  92. 49 0
      crypto/fuzzer/extract_fuzzer_dictionary.sh
  93. 1616 0
      crypto/fuzzer/fuzzer.c
  94. 21 0
      crypto/fuzzer/sanitizer_ignorelist.txt
  95. 787 0
      crypto/groestl.c
  96. 95 0
      crypto/groestl.h
  97. 509 0
      crypto/groestl_internal.h
  98. 157 0
      crypto/hasher.c
  99. 83 0
      crypto/hasher.h
  100. 176 0
      crypto/hmac.c

+ 9 - 0
crypto/.gitignore

@@ -0,0 +1,9 @@
+*.d
+*.exe
+*.o
+*.os
+tests/aestst
+tests/libtrezor-crypto.so
+tests/test_check
+tests/test_openssl
+tests/test_speed

+ 3 - 0
crypto/.gitmodules

@@ -0,0 +1,3 @@
+[submodule "tests/wycheproof"]
+	path = tests/wycheproof
+	url = https://github.com/google/wycheproof

+ 12 - 0
crypto/.gitrepo

@@ -0,0 +1,12 @@
+; DO NOT EDIT (unless you know what you are doing)
+;
+; This subdirectory is a git "subrepo", and this file is maintained by the
+; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme
+;
+[subrepo]
+	remote = git+ssh://git@github.com/trezor/trezor-crypto
+	branch = master
+	commit = 915b3dbbbf58c262865647728a3463b8785fc965
+	parent = 6ad3294f31a1e7484b43c104ff2880b965198cad
+	method = rebase
+	cmdver = 0.4.0

+ 2 - 0
crypto/AUTHORS

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

+ 16 - 0
crypto/CONTRIBUTORS

@@ -0,0 +1,16 @@
+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>

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

+ 45 - 0
crypto/README.md

@@ -0,0 +1,45 @@
+# trezor-crypto
+
+[![Build Status](https://travis-ci.org/trezor/trezor-crypto.svg?branch=master)](https://travis-ci.org/trezor/trezor-crypto) [![gitter](https://badges.gitter.im/trezor/community.svg)](https://gitter.im/trezor/community)
+
+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

+ 94 - 0
crypto/address.c

@@ -0,0 +1,94 @@
+/**
+ * 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

+ 40 - 0
crypto/address.h

@@ -0,0 +1,40 @@
+/**
+ * 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

+ 226 - 0
crypto/aes/aes.h

@@ -0,0 +1,226 @@
+/*
+---------------------------------------------------------------------------
+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

+ 957 - 0
crypto/aes/aes_modes.c

@@ -0,0 +1,957 @@
+/*
+---------------------------------------------------------------------------
+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

+ 307 - 0
crypto/aes/aescrypt.c

@@ -0,0 +1,307 @@
+/*
+---------------------------------------------------------------------------
+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

+ 560 - 0
crypto/aes/aeskey.c

@@ -0,0 +1,560 @@
+/*
+---------------------------------------------------------------------------
+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

+ 784 - 0
crypto/aes/aesopt.h

@@ -0,0 +1,784 @@
+/*
+---------------------------------------------------------------------------
+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

+ 418 - 0
crypto/aes/aestab.c

@@ -0,0 +1,418 @@
+/*
+---------------------------------------------------------------------------
+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
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

+ 182 - 0
crypto/aes/aestst.c

@@ -0,0 +1,182 @@
+/*
+ ---------------------------------------------------------------------------
+ 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
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
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;
+  }
+}

+ 44 - 0
crypto/base32.h

@@ -0,0 +1,44 @@
+/**
+ * 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

+ 221 - 0
crypto/base58.c

@@ -0,0 +1,221 @@
+/**
+ * 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;
+}

+ 46 - 0
crypto/base58.h

@@ -0,0 +1,46 @@
+/**
+ * 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

+ 1848 - 0
crypto/bignum.c

@@ -0,0 +1,1848 @@
+/**
+ * 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

+ 175 - 0
crypto/bignum.h

@@ -0,0 +1,175 @@
+/**
+ * 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

+ 817 - 0
crypto/bip32.c

@@ -0,0 +1,817 @@
+/**
+ * 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"
+#include "aes/aes.h"
+#include "base58.h"
+#include "bignum.h"
+#include "bip32.h"
+#include "cardano.h"
+#include "curves.h"
+#include "ecdsa.h"
+#include "ed25519-donna/ed25519-sha3.h"
+#include "ed25519-donna/ed25519.h"
+#include "hmac.h"
+#include "nist256p1.h"
+#include "secp256k1.h"
+#include "sha2.h"
+#include "sha3.h"
+#if USE_KECCAK
+#include "ed25519-donna/ed25519-keccak.h"
+#endif
+#if USE_NEM
+#include "nem.h"
+#endif
+#include "memzero.h"
+
+const curve_info ed25519_info = {
+    .bip32_name = ED25519_SEED_NAME,
+    .params = NULL,
+    .hasher_base58 = HASHER_SHA2D,
+    .hasher_sign = HASHER_SHA2D,
+    .hasher_pubkey = HASHER_SHA2_RIPEMD,
+    .hasher_script = HASHER_SHA2,
+};
+
+const curve_info ed25519_sha3_info = {
+    .bip32_name = "ed25519-sha3 seed",
+    .params = NULL,
+    .hasher_base58 = HASHER_SHA2D,
+    .hasher_sign = HASHER_SHA2D,
+    .hasher_pubkey = HASHER_SHA2_RIPEMD,
+    .hasher_script = HASHER_SHA2,
+};
+
+#if USE_KECCAK
+const curve_info ed25519_keccak_info = {
+    .bip32_name = "ed25519-keccak seed",
+    .params = NULL,
+    .hasher_base58 = HASHER_SHA2D,
+    .hasher_sign = HASHER_SHA2D,
+    .hasher_pubkey = HASHER_SHA2_RIPEMD,
+    .hasher_script = HASHER_SHA2,
+};
+#endif
+
+const curve_info curve25519_info = {
+    .bip32_name = "curve25519 seed",
+    .params = NULL,
+    .hasher_base58 = HASHER_SHA2D,
+    .hasher_sign = HASHER_SHA2D,
+    .hasher_pubkey = HASHER_SHA2_RIPEMD,
+    .hasher_script = HASHER_SHA2,
+};
+
+int hdnode_from_xpub(uint32_t depth, uint32_t child_num,
+                     const uint8_t *chain_code, const uint8_t *public_key,
+                     const char *curve, HDNode *out) {
+  const curve_info *info = get_curve_by_name(curve);
+  if (info == 0) {
+    return 0;
+  }
+  if (public_key[0] != 0x02 && public_key[0] != 0x03) {  // invalid pubkey
+    return 0;
+  }
+  out->curve = info;
+  out->depth = depth;
+  out->child_num = child_num;
+  memcpy(out->chain_code, chain_code, 32);
+  memzero(out->private_key, 32);
+  memzero(out->private_key_extension, 32);
+  memcpy(out->public_key, public_key, 33);
+  return 1;
+}
+
+int hdnode_from_xprv(uint32_t depth, uint32_t child_num,
+                     const uint8_t *chain_code, const uint8_t *private_key,
+                     const char *curve, HDNode *out) {
+  bool failed = false;
+  const curve_info *info = get_curve_by_name(curve);
+  if (info == 0) {
+    failed = true;
+  } else if (info->params) {
+    bignum256 a = {0};
+    bn_read_be(private_key, &a);
+    if (bn_is_zero(&a)) {  // == 0
+      failed = true;
+    } else {
+      if (!bn_is_less(&a, &info->params->order)) {  // >= order
+        failed = true;
+      }
+    }
+    memzero(&a, sizeof(a));
+  }
+
+  if (failed) {
+    return 0;
+  }
+
+  out->curve = info;
+  out->depth = depth;
+  out->child_num = child_num;
+  memcpy(out->chain_code, chain_code, 32);
+  memcpy(out->private_key, private_key, 32);
+  memzero(out->public_key, sizeof(out->public_key));
+  memzero(out->private_key_extension, sizeof(out->private_key_extension));
+  return 1;
+}
+
+int hdnode_from_seed(const uint8_t *seed, int seed_len, const char *curve,
+                     HDNode *out) {
+  static CONFIDENTIAL uint8_t I[32 + 32];
+  memzero(out, sizeof(HDNode));
+  out->depth = 0;
+  out->child_num = 0;
+  out->curve = get_curve_by_name(curve);
+  if (out->curve == 0) {
+    return 0;
+  }
+  static CONFIDENTIAL HMAC_SHA512_CTX ctx;
+  hmac_sha512_Init(&ctx, (const uint8_t *)out->curve->bip32_name,
+                   strlen(out->curve->bip32_name));
+  hmac_sha512_Update(&ctx, seed, seed_len);
+  hmac_sha512_Final(&ctx, I);
+
+  if (out->curve->params) {
+    bignum256 a = {0};
+    while (true) {
+      bn_read_be(I, &a);
+      if (!bn_is_zero(&a)                                   // != 0
+          && bn_is_less(&a, &out->curve->params->order)) {  // < order
+        break;
+      }
+      hmac_sha512_Init(&ctx, (const uint8_t *)out->curve->bip32_name,
+                       strlen(out->curve->bip32_name));
+      hmac_sha512_Update(&ctx, I, sizeof(I));
+      hmac_sha512_Final(&ctx, I);
+    }
+    memzero(&a, sizeof(a));
+  }
+  memcpy(out->private_key, I, 32);
+  memcpy(out->chain_code, I + 32, 32);
+  memzero(out->public_key, sizeof(out->public_key));
+  memzero(I, sizeof(I));
+  return 1;
+}
+
+uint32_t hdnode_fingerprint(HDNode *node) {
+  uint8_t digest[32] = {0};
+  uint32_t fingerprint = 0;
+
+  hdnode_fill_public_key(node);
+  hasher_Raw(node->curve->hasher_pubkey, node->public_key, 33, digest);
+  fingerprint = ((uint32_t)digest[0] << 24) + (digest[1] << 16) +
+                (digest[2] << 8) + digest[3];
+  memzero(digest, sizeof(digest));
+  return fingerprint;
+}
+
+int hdnode_private_ckd_bip32(HDNode *inout, uint32_t i) {
+  static CONFIDENTIAL uint8_t data[1 + 32 + 4];
+  static CONFIDENTIAL uint8_t I[32 + 32];
+  static CONFIDENTIAL bignum256 a, b;
+
+#if USE_CARDANO
+  if (inout->curve == &ed25519_cardano_info) {
+    return 0;
+  }
+#endif
+
+  if (i & 0x80000000) {  // private derivation
+    data[0] = 0;
+    memcpy(data + 1, inout->private_key, 32);
+  } else {  // public derivation
+    if (!inout->curve->params) {
+      return 0;
+    }
+    if (hdnode_fill_public_key(inout) != 0) {
+      return 0;
+    }
+    memcpy(data, inout->public_key, 33);
+  }
+  write_be(data + 33, i);
+
+  bn_read_be(inout->private_key, &a);
+
+  static CONFIDENTIAL HMAC_SHA512_CTX ctx;
+  hmac_sha512_Init(&ctx, inout->chain_code, 32);
+  hmac_sha512_Update(&ctx, data, sizeof(data));
+  hmac_sha512_Final(&ctx, I);
+
+  if (inout->curve->params) {
+    while (true) {
+      bool failed = false;
+      bn_read_be(I, &b);
+      if (!bn_is_less(&b, &inout->curve->params->order)) {  // >= order
+        failed = true;
+      } else {
+        bn_add(&b, &a);
+        bn_mod(&b, &inout->curve->params->order);
+        if (bn_is_zero(&b)) {
+          failed = true;
+        }
+      }
+
+      if (!failed) {
+        bn_write_be(&b, inout->private_key);
+        break;
+      }
+
+      data[0] = 1;
+      memcpy(data + 1, I + 32, 32);
+      hmac_sha512_Init(&ctx, inout->chain_code, 32);
+      hmac_sha512_Update(&ctx, data, sizeof(data));
+      hmac_sha512_Final(&ctx, I);
+    }
+  } else {
+    memcpy(inout->private_key, I, 32);
+  }
+
+  memcpy(inout->chain_code, I + 32, 32);
+  inout->depth++;
+  inout->child_num = i;
+  memzero(inout->public_key, sizeof(inout->public_key));
+
+  // making sure to wipe our memory
+  memzero(&a, sizeof(a));
+  memzero(&b, sizeof(b));
+  memzero(I, sizeof(I));
+  memzero(data, sizeof(data));
+  return 1;
+}
+
+int hdnode_private_ckd(HDNode *inout, uint32_t i) {
+#if USE_CARDANO
+  if (inout->curve == &ed25519_cardano_info) {
+    return hdnode_private_ckd_cardano(inout, i);
+  } else
+#endif
+  {
+    return hdnode_private_ckd_bip32(inout, i);
+  }
+}
+
+int hdnode_public_ckd_cp(const ecdsa_curve *curve, const curve_point *parent,
+                         const uint8_t *parent_chain_code, uint32_t i,
+                         curve_point *child, uint8_t *child_chain_code) {
+  uint8_t data[(1 + 32) + 4] = {0};
+  uint8_t I[32 + 32] = {0};
+  bignum256 c = {0};
+
+  if (i & 0x80000000) {  // private derivation
+    return 0;
+  }
+
+  data[0] = 0x02 | (parent->y.val[0] & 0x01);
+  bn_write_be(&parent->x, data + 1);
+  write_be(data + 33, i);
+
+  while (true) {
+    hmac_sha512(parent_chain_code, 32, data, sizeof(data), I);
+    bn_read_be(I, &c);
+    if (bn_is_less(&c, &curve->order)) {  // < order
+      scalar_multiply(curve, &c, child);  // b = c * G
+      point_add(curve, parent, child);    // b = a + b
+      if (!point_is_infinity(child)) {
+        if (child_chain_code) {
+          memcpy(child_chain_code, I + 32, 32);
+        }
+
+        // Wipe all stack data.
+        memzero(data, sizeof(data));
+        memzero(I, sizeof(I));
+        memzero(&c, sizeof(c));
+        return 1;
+      }
+    }
+
+    data[0] = 1;
+    memcpy(data + 1, I + 32, 32);
+  }
+}
+
+int hdnode_public_ckd(HDNode *inout, uint32_t i) {
+  curve_point parent = {0}, child = {0};
+
+  if (!ecdsa_read_pubkey(inout->curve->params, inout->public_key, &parent)) {
+    return 0;
+  }
+  if (!hdnode_public_ckd_cp(inout->curve->params, &parent, inout->chain_code, i,
+                            &child, inout->chain_code)) {
+    return 0;
+  }
+  memzero(inout->private_key, 32);
+  inout->depth++;
+  inout->child_num = i;
+  inout->public_key[0] = 0x02 | (child.y.val[0] & 0x01);
+  bn_write_be(&child.x, inout->public_key + 1);
+
+  // Wipe all stack data.
+  memzero(&parent, sizeof(parent));
+  memzero(&child, sizeof(child));
+
+  return 1;
+}
+
+void hdnode_public_ckd_address_optimized(const curve_point *pub,
+                                         const uint8_t *chain_code, uint32_t i,
+                                         uint32_t version,
+                                         HasherType hasher_pubkey,
+                                         HasherType hasher_base58, char *addr,
+                                         int addrsize, int addrformat) {
+  uint8_t child_pubkey[33] = {0};
+  curve_point b = {0};
+
+  hdnode_public_ckd_cp(&secp256k1, pub, chain_code, i, &b, NULL);
+  child_pubkey[0] = 0x02 | (b.y.val[0] & 0x01);
+  bn_write_be(&b.x, child_pubkey + 1);
+
+  switch (addrformat) {
+    case 1:  // Segwit-in-P2SH
+      ecdsa_get_address_segwit_p2sh(child_pubkey, version, hasher_pubkey,
+                                    hasher_base58, addr, addrsize);
+      break;
+    default:  // normal address
+      ecdsa_get_address(child_pubkey, version, hasher_pubkey, hasher_base58,
+                        addr, addrsize);
+      break;
+  }
+}
+
+#if USE_BIP32_CACHE
+static bool private_ckd_cache_root_set = false;
+static CONFIDENTIAL HDNode private_ckd_cache_root;
+static int private_ckd_cache_index = 0;
+
+static CONFIDENTIAL struct {
+  bool set;
+  size_t depth;
+  uint32_t i[BIP32_CACHE_MAXDEPTH];
+  HDNode node;
+} private_ckd_cache[BIP32_CACHE_SIZE];
+
+void bip32_cache_clear(void) {
+  private_ckd_cache_root_set = false;
+  private_ckd_cache_index = 0;
+  memzero(&private_ckd_cache_root, sizeof(private_ckd_cache_root));
+  memzero(private_ckd_cache, sizeof(private_ckd_cache));
+}
+
+int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count,
+                              uint32_t *fingerprint) {
+  if (i_count == 0) {
+    // no way how to compute parent fingerprint
+    return 1;
+  }
+  if (i_count == 1) {
+    if (fingerprint) {
+      *fingerprint = hdnode_fingerprint(inout);
+    }
+    if (hdnode_private_ckd(inout, i[0]) == 0) return 0;
+    return 1;
+  }
+
+  bool found = false;
+  // if root is not set or not the same
+  if (!private_ckd_cache_root_set ||
+      memcmp(&private_ckd_cache_root, inout, sizeof(HDNode)) != 0) {
+    // clear the cache
+    private_ckd_cache_index = 0;
+    memzero(private_ckd_cache, sizeof(private_ckd_cache));
+    // setup new root
+    memcpy(&private_ckd_cache_root, inout, sizeof(HDNode));
+    private_ckd_cache_root_set = true;
+  } else {
+    // try to find parent
+    int j = 0;
+    for (j = 0; j < BIP32_CACHE_SIZE; j++) {
+      if (private_ckd_cache[j].set &&
+          private_ckd_cache[j].depth == i_count - 1 &&
+          memcmp(private_ckd_cache[j].i, i, (i_count - 1) * sizeof(uint32_t)) ==
+              0 &&
+          private_ckd_cache[j].node.curve == inout->curve) {
+        memcpy(inout, &(private_ckd_cache[j].node), sizeof(HDNode));
+        found = true;
+        break;
+      }
+    }
+  }
+
+  // else derive parent
+  if (!found) {
+    size_t k = 0;
+    for (k = 0; k < i_count - 1; k++) {
+      if (hdnode_private_ckd(inout, i[k]) == 0) return 0;
+    }
+    // and save it
+    memzero(&(private_ckd_cache[private_ckd_cache_index]),
+            sizeof(private_ckd_cache[private_ckd_cache_index]));
+    private_ckd_cache[private_ckd_cache_index].set = true;
+    private_ckd_cache[private_ckd_cache_index].depth = i_count - 1;
+    memcpy(private_ckd_cache[private_ckd_cache_index].i, i,
+           (i_count - 1) * sizeof(uint32_t));
+    memcpy(&(private_ckd_cache[private_ckd_cache_index].node), inout,
+           sizeof(HDNode));
+    private_ckd_cache_index = (private_ckd_cache_index + 1) % BIP32_CACHE_SIZE;
+  }
+
+  if (fingerprint) {
+    *fingerprint = hdnode_fingerprint(inout);
+  }
+  if (hdnode_private_ckd(inout, i[i_count - 1]) == 0) return 0;
+
+  return 1;
+}
+#endif
+
+int hdnode_get_address_raw(HDNode *node, uint32_t version, uint8_t *addr_raw) {
+  if (hdnode_fill_public_key(node) != 0) {
+    return 1;
+  }
+  ecdsa_get_address_raw(node->public_key, version, node->curve->hasher_pubkey,
+                        addr_raw);
+  return 0;
+}
+
+int hdnode_get_address(HDNode *node, uint32_t version, char *addr,
+                       int addrsize) {
+  if (hdnode_fill_public_key(node) != 0) {
+    return 1;
+  }
+  ecdsa_get_address(node->public_key, version, node->curve->hasher_pubkey,
+                    node->curve->hasher_base58, addr, addrsize);
+  return 0;
+}
+
+int hdnode_fill_public_key(HDNode *node) {
+  if (node->public_key[0] != 0) return 0;
+
+#if USE_BIP32_25519_CURVES
+  if (node->curve->params) {
+    if (ecdsa_get_public_key33(node->curve->params, node->private_key,
+                               node->public_key) != 0) {
+      return 1;
+    }
+  } else {
+    node->public_key[0] = 1;
+    if (node->curve == &ed25519_info) {
+      ed25519_publickey(node->private_key, node->public_key + 1);
+    } else if (node->curve == &ed25519_sha3_info) {
+      ed25519_publickey_sha3(node->private_key, node->public_key + 1);
+#if USE_KECCAK
+    } else if (node->curve == &ed25519_keccak_info) {
+      ed25519_publickey_keccak(node->private_key, node->public_key + 1);
+#endif
+    } else if (node->curve == &curve25519_info) {
+      curve25519_scalarmult_basepoint(node->public_key + 1, node->private_key);
+#if USE_CARDANO
+    } else if (node->curve == &ed25519_cardano_info) {
+      ed25519_publickey_ext(node->private_key, node->public_key + 1);
+#endif
+    }
+  }
+#else
+
+  if (ecdsa_get_public_key33(node->curve->params, node->private_key,
+                             node->public_key) != 0) {
+    return 1;
+  }
+#endif
+  return 0;
+}
+
+#if USE_ETHEREUM
+int hdnode_get_ethereum_pubkeyhash(const HDNode *node, uint8_t *pubkeyhash) {
+  uint8_t buf[65] = {0};
+  SHA3_CTX ctx = {0};
+
+  /* get uncompressed public key */
+  if (ecdsa_get_public_key65(node->curve->params, node->private_key, buf) !=
+      0) {
+    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);
+
+  /* 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;
+}

+ 149 - 0
crypto/bip32.h

@@ -0,0 +1,149 @@
+/**
+ * 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

+ 286 - 0
crypto/bip39.c

@@ -0,0 +1,286 @@
+/**
+ * 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 = strnlen(passphrase, 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;
+}

+ 60 - 0
crypto/bip39.h

@@ -0,0 +1,60 @@
+/**
+ * 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

+ 369 - 0
crypto/bip39_english.c

@@ -0,0 +1,369 @@
+/**
+ * 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",
+};

+ 234 - 0
crypto/blake256.c

@@ -0,0 +1,234 @@
+/*
+   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
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__ */

+ 44 - 0
crypto/blake2_common.h

@@ -0,0 +1,44 @@
+
+#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));
+}

+ 324 - 0
crypto/blake2b.c

@@ -0,0 +1,324 @@
+/*
+   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;
+}

+ 41 - 0
crypto/blake2b.h

@@ -0,0 +1,41 @@
+#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

+ 318 - 0
crypto/blake2s.c

@@ -0,0 +1,318 @@
+/*
+   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;
+}

+ 41 - 0
crypto/blake2s.h

@@ -0,0 +1,41 @@
+#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

+ 59 - 0
crypto/byte_order.h

@@ -0,0 +1,59 @@
+#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

+ 306 - 0
crypto/cardano.c

@@ -0,0 +1,306 @@
+/**
+ * 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

+ 54 - 0
crypto/cardano.h

@@ -0,0 +1,54 @@
+/**
+ * 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__

+ 189 - 0
crypto/cash_addr.c

@@ -0,0 +1,189 @@
+/* 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;
+}

+ 77 - 0
crypto/cash_addr.h

@@ -0,0 +1,77 @@
+/* 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
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.

+ 60 - 0
crypto/chacha20poly1305/chacha20poly1305.c

@@ -0,0 +1,60 @@
+// 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);
+}

+ 19 - 0
crypto/chacha20poly1305/chacha20poly1305.h

@@ -0,0 +1,19 @@
+#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

+ 252 - 0
crypto/chacha20poly1305/chacha_merged.c

@@ -0,0 +1,252 @@
+/*
+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
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
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
+
+/* ------------------------------------------------------------------------- */

+ 275 - 0
crypto/chacha20poly1305/ecrypt-portable.h

@@ -0,0 +1,275 @@
+/* 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

+ 290 - 0
crypto/chacha20poly1305/ecrypt-sync.h

@@ -0,0 +1,290 @@
+#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
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

+ 219 - 0
crypto/chacha20poly1305/poly1305-donna-32.h

@@ -0,0 +1,219 @@
+/*
+	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;
+}
+

+ 179 - 0
crypto/chacha20poly1305/poly1305-donna.c

@@ -0,0 +1,179 @@
+#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;
+}

+ 20 - 0
crypto/chacha20poly1305/poly1305-donna.h

@@ -0,0 +1,20 @@
+#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 */
+

+ 48 - 0
crypto/chacha20poly1305/rfc7539.c

@@ -0,0 +1,48 @@
+// 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
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

+ 126 - 0
crypto/chacha_drbg.c

@@ -0,0 +1,126 @@
+/*
+ * 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;
+}

+ 54 - 0
crypto/chacha_drbg.h

@@ -0,0 +1,54 @@
+/*
+ * 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__

+ 30 - 0
crypto/check_mem.h

@@ -0,0 +1,30 @@
+#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
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
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

+ 1251 - 0
crypto/ecdsa.c

@@ -0,0 +1,1251 @@
+/**
+ * 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;
+}

+ 128 - 0
crypto/ecdsa.h

@@ -0,0 +1,128 @@
+/**
+ * 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
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)

+ 681 - 0
crypto/ed25519-donna/curve25519-donna-32bit.c

@@ -0,0 +1,681 @@
+/*
+	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
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
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
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);

+ 67 - 0
crypto/ed25519-donna/curve25519-donna-scalarmult-base.c

@@ -0,0 +1,67 @@
+#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);
+}

+ 8 - 0
crypto/ed25519-donna/curve25519-donna-scalarmult-base.h

@@ -0,0 +1,8 @@
+/* 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);

+ 63 - 0
crypto/ed25519-donna/ed25519-donna-32bit-tables.c

@@ -0,0 +1,63 @@
+#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
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];

+ 261 - 0
crypto/ed25519-donna/ed25519-donna-basepoint-table.c

@@ -0,0 +1,261 @@
+#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
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];

+ 730 - 0
crypto/ed25519-donna/ed25519-donna-impl-base.c

@@ -0,0 +1,730 @@
+#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);
+}

+ 104 - 0
crypto/ed25519-donna/ed25519-donna-impl-base.h

@@ -0,0 +1,104 @@
+/*
+	Timing safe memory compare
+*/
+int ed25519_verify(const unsigned char *x, const unsigned char *y, size_t len);
+
+/*
+	conversions
+*/
+
+void ge25519_p1p1_to_partial(ge25519 *r, const ge25519_p1p1 *p);
+
+void ge25519_p1p1_to_full(ge25519 *r, const ge25519_p1p1 *p);
+
+void ge25519_full_to_pniels(ge25519_pniels *p, const ge25519 *r);
+
+/*
+	adding & doubling
+*/
+
+void ge25519_double_p1p1(ge25519_p1p1 *r, const ge25519 *p);
+
+#ifndef ED25519_NO_PRECOMP
+void ge25519_nielsadd2_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519_niels *q, unsigned char signbit);
+#endif
+
+/* computes [s1]p1 + [s2]p2 */
+#if USE_MONERO
+void ge25519_double_scalarmult_vartime2(ge25519 *r, const ge25519 *p1, const bignum256modm s1, const ge25519 *p2, const bignum256modm s2);
+#endif
+
+void ge25519_pnielsadd_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519_pniels *q, unsigned char signbit);
+
+void ge25519_double_partial(ge25519 *r, const ge25519 *p);
+
+void ge25519_double(ge25519 *r, const ge25519 *p);
+
+void ge25519_nielsadd2(ge25519 *r, const ge25519_niels *q);
+
+void ge25519_pnielsadd(ge25519_pniels *r, const ge25519 *p, const ge25519_pniels *q);
+
+
+/*
+	pack & unpack
+*/
+
+void ge25519_pack(unsigned char r[32], const ge25519 *p);
+
+int ge25519_unpack_negative_vartime(ge25519 *r, const unsigned char p[32]);
+
+/*
+	scalarmults
+*/
+
+void ge25519_set_neutral(ge25519 *r);
+
+/* computes [s1]p1 + [s2]base */
+void ge25519_double_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const bignum256modm s1, const bignum256modm s2);
+
+/* computes [s1]p1, constant time */
+void ge25519_scalarmult(ge25519 *r, const ge25519 *p1, const bignum256modm s1);
+
+void ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[256][96], uint32_t pos, signed char b);
+
+/* computes [s]basepoint */
+void ge25519_scalarmult_base_niels(ge25519 *r, const uint8_t basepoint_table[256][96], const bignum256modm s);
+
+/* check if r is on curve */
+int ge25519_check(const ge25519 *r);
+
+/* a == b */
+int ge25519_eq(const ge25519 *a, const ge25519 *b);
+
+/* copies one point to another */
+void ge25519_copy(ge25519 *dst, const ge25519 *src);
+
+/* sets B point to r */
+void ge25519_set_base(ge25519 *r);
+
+/* 8*P */
+void ge25519_mul8(ge25519 *r, const ge25519 *t);
+
+/* -P */
+void ge25519_neg_partial(ge25519 *r);
+
+/* -P */
+void ge25519_neg_full(ge25519 *r);
+
+/* reduce all coords */
+void ge25519_reduce(ge25519 *r, const ge25519 *t);
+
+/* normalizes coords. (x, y, 1, x*y) */
+void ge25519_norm(ge25519 *r, const ge25519 * t);
+
+/* Simple addition */
+void ge25519_add(ge25519 *r, const ge25519 *a, const ge25519 *b, unsigned char signbit);
+
+/* point from bytes, used in H_p() */
+void ge25519_fromfe_frombytes_vartime(ge25519 *r, const unsigned char *s);
+
+/* point from bytes */
+int ge25519_unpack_vartime(ge25519 *r, const unsigned char *s);
+
+/* aG, wrapper for niels base mult. */
+void ge25519_scalarmult_base_wrapper(ge25519 *r, const bignum256modm s);

+ 24 - 0
crypto/ed25519-donna/ed25519-donna-portable.h

@@ -0,0 +1,24 @@
+#define mul32x32_64(a,b) (((uint64_t)(a))*(b))
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+#define DONNA_INLINE
+#undef ALIGN
+#define ALIGN(x) __attribute__((aligned(x)))
+
+static inline void U32TO8_LE(unsigned char *p, const uint32_t v) {
+	p[0] = (unsigned char)(v      );
+	p[1] = (unsigned char)(v >>  8);
+	p[2] = (unsigned char)(v >> 16);
+	p[3] = (unsigned char)(v >> 24);
+}
+
+static inline uint32_t U8TO32_LE(const unsigned char *p) {
+	return
+	(((uint32_t)(p[0])      ) |
+	 ((uint32_t)(p[1]) <<  8) |
+	 ((uint32_t)(p[2]) << 16) |
+	 ((uint32_t)(p[3]) << 24));
+}

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

+ 23 - 0
crypto/ed25519-donna/ed25519-hash-custom-keccak.h

@@ -0,0 +1,23 @@
+/*
+	a custom hash must have a 512bit digest and implement:
+
+	struct ed25519_hash_context;
+
+	void ed25519_hash_init(ed25519_hash_context *ctx);
+	void ed25519_hash_update(ed25519_hash_context *ctx, const uint8_t *in, size_t inlen);
+	void ed25519_hash_final(ed25519_hash_context *ctx, uint8_t *hash);
+	void ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen);
+*/
+
+#ifndef ED25519_HASH_CUSTOM
+#define ED25519_HASH_CUSTOM
+
+#include "sha3.h"
+
+#define ed25519_hash_context SHA3_CTX
+#define ed25519_hash_init(ctx) keccak_512_Init(ctx)
+#define ed25519_hash_update(ctx, in, inlen) keccak_Update((ctx), (in), (inlen))
+#define ed25519_hash_final(ctx, hash) keccak_Final((ctx), (hash))
+#define ed25519_hash(hash, in, inlen) keccak_512((in), (inlen), (hash))
+
+#endif // ED25519_HASH_CUSTOM

+ 23 - 0
crypto/ed25519-donna/ed25519-hash-custom-sha3.h

@@ -0,0 +1,23 @@
+/*
+	a custom hash must have a 512bit digest and implement:
+
+	struct ed25519_hash_context;
+
+	void ed25519_hash_init(ed25519_hash_context *ctx);
+	void ed25519_hash_update(ed25519_hash_context *ctx, const uint8_t *in, size_t inlen);
+	void ed25519_hash_final(ed25519_hash_context *ctx, uint8_t *hash);
+	void ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen);
+*/
+
+#ifndef ED25519_HASH_CUSTOM
+#define ED25519_HASH_CUSTOM
+
+#include "sha3.h"
+
+#define ed25519_hash_context SHA3_CTX
+#define ed25519_hash_init(ctx) sha3_512_Init(ctx)
+#define ed25519_hash_update(ctx, in, inlen) sha3_Update((ctx), (in), (inlen))
+#define ed25519_hash_final(ctx, hash) sha3_Final((ctx), (hash))
+#define ed25519_hash(hash, in, inlen) sha3_512((in), (inlen), (hash))
+
+#endif // ED25519_HASH_CUSTOM

+ 23 - 0
crypto/ed25519-donna/ed25519-hash-custom.h

@@ -0,0 +1,23 @@
+/*
+	a custom hash must have a 512bit digest and implement:
+
+	struct ed25519_hash_context;
+
+	void ed25519_hash_init(ed25519_hash_context *ctx);
+	void ed25519_hash_update(ed25519_hash_context *ctx, const uint8_t *in, size_t inlen);
+	void ed25519_hash_final(ed25519_hash_context *ctx, uint8_t *hash);
+	void ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen);
+*/
+
+#ifndef ED25519_HASH_CUSTOM
+#define ED25519_HASH_CUSTOM
+
+#include "sha2.h"
+
+#define ed25519_hash_context SHA512_CTX
+#define ed25519_hash_init(ctx) sha512_Init(ctx)
+#define ed25519_hash_update(ctx, in, inlen) sha512_Update((ctx), (in), (inlen))
+#define ed25519_hash_final(ctx, hash) sha512_Final((ctx), (hash))
+#define ed25519_hash(hash, in, inlen) sha512_Raw((in), (inlen), (hash))
+
+#endif // ED25519_HASH_CUSTOM

+ 8 - 0
crypto/ed25519-donna/ed25519-keccak.c

@@ -0,0 +1,8 @@
+#include <stddef.h>
+
+#include "ed25519-keccak.h"
+#include "ed25519-hash-custom-keccak.h"
+
+#define ED25519_SUFFIX _keccak
+
+#include "ed25519.c"

+ 21 - 0
crypto/ed25519-donna/ed25519-keccak.h

@@ -0,0 +1,21 @@
+#ifndef ED25519_KECCAK_H
+#define ED25519_KECCAK_H
+
+#include "ed25519.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+void ed25519_publickey_keccak(const ed25519_secret_key sk, ed25519_public_key pk);
+
+int ed25519_sign_open_keccak(const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS);
+void ed25519_sign_keccak(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, ed25519_signature RS);
+
+int ed25519_scalarmult_keccak(ed25519_public_key res, const ed25519_secret_key sk, const ed25519_public_key pk);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif // ED25519_KECCAK_H

+ 8 - 0
crypto/ed25519-donna/ed25519-sha3.c

@@ -0,0 +1,8 @@
+#include <stddef.h>
+
+#include "ed25519-sha3.h"
+#include "ed25519-hash-custom-sha3.h"
+
+#define ED25519_SUFFIX _sha3
+
+#include "ed25519.c"

+ 21 - 0
crypto/ed25519-donna/ed25519-sha3.h

@@ -0,0 +1,21 @@
+#ifndef ED25519_SHA3_H
+#define ED25519_SHA3_H
+
+#include "ed25519.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+void ed25519_publickey_sha3(const ed25519_secret_key sk, ed25519_public_key pk);
+
+int ed25519_sign_open_sha3(const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS);
+void ed25519_sign_sha3(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, ed25519_signature RS);
+
+int ed25519_scalarmult_sha3(ed25519_public_key res, const ed25519_secret_key sk, const ed25519_public_key pk);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif // ED25519_SHA3_H

+ 318 - 0
crypto/ed25519-donna/ed25519.c

@@ -0,0 +1,318 @@
+/*
+	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

+ 45 - 0
crypto/ed25519-donna/ed25519.h

@@ -0,0 +1,45 @@
+#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

+ 517 - 0
crypto/ed25519-donna/modm-donna-32bit.c

@@ -0,0 +1,517 @@
+/*
+	Public domain by Andrew M. <liquidsun@gmail.com>
+*/
+
+#include "ed25519-donna.h"
+
+/*
+	Arithmetic modulo the group order n = 2^252 +  27742317777372353535851937790883648493 = 7237005577332262213973186563042994240857116359379907606001950938285454250989
+
+	k = 32
+	b = 1 << 8 = 256
+	m = 2^252 + 27742317777372353535851937790883648493 = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed
+	mu = floor( b^(k*2) / m ) = 0xfffffffffffffffffffffffffffffffeb2106215d086329a7ed9ce5a30a2c131b
+*/
+
+static const bignum256modm modm_m = {
+	0x1cf5d3ed, 0x20498c69, 0x2f79cd65, 0x37be77a8,
+	0x00000014,	0x00000000, 0x00000000,	0x00000000,
+	0x00001000
+};
+
+static const bignum256modm modm_mu = {
+	0x0a2c131b, 0x3673968c, 0x06329a7e, 0x01885742,
+	0x3fffeb21, 0x3fffffff, 0x3fffffff, 0x3fffffff,
+	0x000fffff
+};
+
+static bignum256modm_element_t
+lt_modm(bignum256modm_element_t a, bignum256modm_element_t b) {
+	return (a - b) >> 31;
+}
+
+/* see HAC, Alg. 14.42 Step 4 */
+void reduce256_modm(bignum256modm r) {
+	bignum256modm t = {0};
+	bignum256modm_element_t b = 0, pb = 0, mask = 0;
+
+	/* t = r - m */
+	pb = 0;
+	pb += modm_m[0]; b = lt_modm(r[0], pb); t[0] = (r[0] - pb + (b << 30)); pb = b;
+	pb += modm_m[1]; b = lt_modm(r[1], pb); t[1] = (r[1] - pb + (b << 30)); pb = b;
+	pb += modm_m[2]; b = lt_modm(r[2], pb); t[2] = (r[2] - pb + (b << 30)); pb = b;
+	pb += modm_m[3]; b = lt_modm(r[3], pb); t[3] = (r[3] - pb + (b << 30)); pb = b;
+	pb += modm_m[4]; b = lt_modm(r[4], pb); t[4] = (r[4] - pb + (b << 30)); pb = b;
+	pb += modm_m[5]; b = lt_modm(r[5], pb); t[5] = (r[5] - pb + (b << 30)); pb = b;
+	pb += modm_m[6]; b = lt_modm(r[6], pb); t[6] = (r[6] - pb + (b << 30)); pb = b;
+	pb += modm_m[7]; b = lt_modm(r[7], pb); t[7] = (r[7] - pb + (b << 30)); pb = b;
+	pb += modm_m[8]; b = lt_modm(r[8], pb); t[8] = (r[8] - pb + (b << 16));
+
+	/* keep r if r was smaller than m */
+	mask = b - 1;
+	r[0] ^= mask & (r[0] ^ t[0]);
+	r[1] ^= mask & (r[1] ^ t[1]);
+	r[2] ^= mask & (r[2] ^ t[2]);
+	r[3] ^= mask & (r[3] ^ t[3]);
+	r[4] ^= mask & (r[4] ^ t[4]);
+	r[5] ^= mask & (r[5] ^ t[5]);
+	r[6] ^= mask & (r[6] ^ t[6]);
+	r[7] ^= mask & (r[7] ^ t[7]);
+	r[8] ^= mask & (r[8] ^ t[8]);
+}
+
+/*
+	Barrett reduction,  see HAC, Alg. 14.42
+
+	Instead of passing in x, pre-process in to q1 and r1 for efficiency
+*/
+void barrett_reduce256_modm(bignum256modm r, const bignum256modm q1, const bignum256modm r1) {
+	bignum256modm q3 = {0}, r2 = {0};
+	uint64_t c = 0;
+	bignum256modm_element_t f = 0, b = 0, pb = 0;
+
+	/* q1 = x >> 248 = 264 bits = 9 30 bit elements
+	   q2 = mu * q1
+	   q3 = (q2 / 256(32+1)) = q2 / (2^8)^(32+1) = q2 >> 264 */
+	c  = mul32x32_64(modm_mu[0], q1[7]) + mul32x32_64(modm_mu[1], q1[6]) + mul32x32_64(modm_mu[2], q1[5]) + mul32x32_64(modm_mu[3], q1[4]) + mul32x32_64(modm_mu[4], q1[3]) + mul32x32_64(modm_mu[5], q1[2]) + mul32x32_64(modm_mu[6], q1[1]) + mul32x32_64(modm_mu[7], q1[0]);
+	c >>= 30;
+	c += mul32x32_64(modm_mu[0], q1[8]) + mul32x32_64(modm_mu[1], q1[7]) + mul32x32_64(modm_mu[2], q1[6]) + mul32x32_64(modm_mu[3], q1[5]) + mul32x32_64(modm_mu[4], q1[4]) + mul32x32_64(modm_mu[5], q1[3]) + mul32x32_64(modm_mu[6], q1[2]) + mul32x32_64(modm_mu[7], q1[1]) + mul32x32_64(modm_mu[8], q1[0]);
+	f = (bignum256modm_element_t)c; q3[0] = (f >> 24) & 0x3f; c >>= 30;
+	c += mul32x32_64(modm_mu[1], q1[8]) + mul32x32_64(modm_mu[2], q1[7]) + mul32x32_64(modm_mu[3], q1[6]) + mul32x32_64(modm_mu[4], q1[5]) + mul32x32_64(modm_mu[5], q1[4]) + mul32x32_64(modm_mu[6], q1[3]) + mul32x32_64(modm_mu[7], q1[2]) + mul32x32_64(modm_mu[8], q1[1]);
+	f = (bignum256modm_element_t)c; q3[0] |= (f << 6) & 0x3fffffff; q3[1] = (f >> 24) & 0x3f; c >>= 30;
+	c += mul32x32_64(modm_mu[2], q1[8]) + mul32x32_64(modm_mu[3], q1[7]) + mul32x32_64(modm_mu[4], q1[6]) + mul32x32_64(modm_mu[5], q1[5]) + mul32x32_64(modm_mu[6], q1[4]) + mul32x32_64(modm_mu[7], q1[3]) + mul32x32_64(modm_mu[8], q1[2]);
+	f = (bignum256modm_element_t)c; q3[1] |= (f << 6) & 0x3fffffff; q3[2] = (f >> 24) & 0x3f; c >>= 30;
+	c += mul32x32_64(modm_mu[3], q1[8]) + mul32x32_64(modm_mu[4], q1[7]) + mul32x32_64(modm_mu[5], q1[6]) + mul32x32_64(modm_mu[6], q1[5]) + mul32x32_64(modm_mu[7], q1[4]) + mul32x32_64(modm_mu[8], q1[3]);
+	f = (bignum256modm_element_t)c; q3[2] |= (f << 6) & 0x3fffffff; q3[3] = (f >> 24) & 0x3f; c >>= 30;
+	c += mul32x32_64(modm_mu[4], q1[8]) + mul32x32_64(modm_mu[5], q1[7]) + mul32x32_64(modm_mu[6], q1[6]) + mul32x32_64(modm_mu[7], q1[5]) + mul32x32_64(modm_mu[8], q1[4]);
+	f = (bignum256modm_element_t)c; q3[3] |= (f << 6) & 0x3fffffff; q3[4] = (f >> 24) & 0x3f; c >>= 30;
+	c += mul32x32_64(modm_mu[5], q1[8]) + mul32x32_64(modm_mu[6], q1[7]) + mul32x32_64(modm_mu[7], q1[6]) + mul32x32_64(modm_mu[8], q1[5]);
+	f = (bignum256modm_element_t)c; q3[4] |= (f << 6) & 0x3fffffff; q3[5] = (f >> 24) & 0x3f; c >>= 30;
+	c += mul32x32_64(modm_mu[6], q1[8]) + mul32x32_64(modm_mu[7], q1[7]) + mul32x32_64(modm_mu[8], q1[6]);
+	f = (bignum256modm_element_t)c; q3[5] |= (f << 6) & 0x3fffffff; q3[6] = (f >> 24) & 0x3f; c >>= 30;
+	c += mul32x32_64(modm_mu[7], q1[8]) + mul32x32_64(modm_mu[8], q1[7]);
+	f = (bignum256modm_element_t)c; q3[6] |= (f << 6) & 0x3fffffff; q3[7] = (f >> 24) & 0x3f; c >>= 30;
+	c += mul32x32_64(modm_mu[8], q1[8]);
+	f = (bignum256modm_element_t)c; q3[7] |= (f << 6) & 0x3fffffff; q3[8] = (bignum256modm_element_t)(c >> 24);
+
+	/* r1 = (x mod 256^(32+1)) = x mod (2^8)(32+1) = x & ((1 << 264) - 1)
+	   r2 = (q3 * m) mod (256^(32+1)) = (q3 * m) & ((1 << 264) - 1) */
+	c = mul32x32_64(modm_m[0], q3[0]);
+	r2[0] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30;
+	c += mul32x32_64(modm_m[0], q3[1]) + mul32x32_64(modm_m[1], q3[0]);
+	r2[1] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30;
+	c += mul32x32_64(modm_m[0], q3[2]) + mul32x32_64(modm_m[1], q3[1]) + mul32x32_64(modm_m[2], q3[0]);
+	r2[2] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30;
+	c += mul32x32_64(modm_m[0], q3[3]) + mul32x32_64(modm_m[1], q3[2]) + mul32x32_64(modm_m[2], q3[1]) + mul32x32_64(modm_m[3], q3[0]);
+	r2[3] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30;
+	c += mul32x32_64(modm_m[0], q3[4]) + mul32x32_64(modm_m[1], q3[3]) + mul32x32_64(modm_m[2], q3[2]) + mul32x32_64(modm_m[3], q3[1]) + mul32x32_64(modm_m[4], q3[0]);
+	r2[4] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30;
+	c += mul32x32_64(modm_m[0], q3[5]) + mul32x32_64(modm_m[1], q3[4]) + mul32x32_64(modm_m[2], q3[3]) + mul32x32_64(modm_m[3], q3[2]) + mul32x32_64(modm_m[4], q3[1]) + mul32x32_64(modm_m[5], q3[0]);
+	r2[5] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30;
+	c += mul32x32_64(modm_m[0], q3[6]) + mul32x32_64(modm_m[1], q3[5]) + mul32x32_64(modm_m[2], q3[4]) + mul32x32_64(modm_m[3], q3[3]) + mul32x32_64(modm_m[4], q3[2]) + mul32x32_64(modm_m[5], q3[1]) + mul32x32_64(modm_m[6], q3[0]);
+	r2[6] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30;
+	c += mul32x32_64(modm_m[0], q3[7]) + mul32x32_64(modm_m[1], q3[6]) + mul32x32_64(modm_m[2], q3[5]) + mul32x32_64(modm_m[3], q3[4]) + mul32x32_64(modm_m[4], q3[3]) + mul32x32_64(modm_m[5], q3[2]) + mul32x32_64(modm_m[6], q3[1]) + mul32x32_64(modm_m[7], q3[0]);
+	r2[7] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30;
+	c += mul32x32_64(modm_m[0], q3[8]) + mul32x32_64(modm_m[1], q3[7]) + mul32x32_64(modm_m[2], q3[6]) + mul32x32_64(modm_m[3], q3[5]) + mul32x32_64(modm_m[4], q3[4]) + mul32x32_64(modm_m[5], q3[3]) + mul32x32_64(modm_m[6], q3[2]) + mul32x32_64(modm_m[7], q3[1]) + mul32x32_64(modm_m[8], q3[0]);
+	r2[8] = (bignum256modm_element_t)(c & 0xffffff);
+
+	/* r = r1 - r2
+	   if (r < 0) r += (1 << 264) */
+	pb = 0;
+	pb += r2[0]; b = lt_modm(r1[0], pb); r[0] = (r1[0] - pb + (b << 30)); pb = b;
+	pb += r2[1]; b = lt_modm(r1[1], pb); r[1] = (r1[1] - pb + (b << 30)); pb = b;
+	pb += r2[2]; b = lt_modm(r1[2], pb); r[2] = (r1[2] - pb + (b << 30)); pb = b;
+	pb += r2[3]; b = lt_modm(r1[3], pb); r[3] = (r1[3] - pb + (b << 30)); pb = b;
+	pb += r2[4]; b = lt_modm(r1[4], pb); r[4] = (r1[4] - pb + (b << 30)); pb = b;
+	pb += r2[5]; b = lt_modm(r1[5], pb); r[5] = (r1[5] - pb + (b << 30)); pb = b;
+	pb += r2[6]; b = lt_modm(r1[6], pb); r[6] = (r1[6] - pb + (b << 30)); pb = b;
+	pb += r2[7]; b = lt_modm(r1[7], pb); r[7] = (r1[7] - pb + (b << 30)); pb = b;
+	pb += r2[8]; b = lt_modm(r1[8], pb); r[8] = (r1[8] - pb + (b << 24));
+
+	reduce256_modm(r);
+	reduce256_modm(r);
+}
+
+/* addition modulo m */
+void add256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) {
+	bignum256modm_element_t c = 0;
+
+	c  = x[0] + y[0]; r[0] = c & 0x3fffffff; c >>= 30;
+	c += x[1] + y[1]; r[1] = c & 0x3fffffff; c >>= 30;
+	c += x[2] + y[2]; r[2] = c & 0x3fffffff; c >>= 30;
+	c += x[3] + y[3]; r[3] = c & 0x3fffffff; c >>= 30;
+	c += x[4] + y[4]; r[4] = c & 0x3fffffff; c >>= 30;
+	c += x[5] + y[5]; r[5] = c & 0x3fffffff; c >>= 30;
+	c += x[6] + y[6]; r[6] = c & 0x3fffffff; c >>= 30;
+	c += x[7] + y[7]; r[7] = c & 0x3fffffff; c >>= 30;
+	c += x[8] + y[8]; r[8] = c;
+
+	reduce256_modm(r);
+}
+
+/* -x modulo m */
+void neg256_modm(bignum256modm r, const bignum256modm x) {
+	bignum256modm_element_t b = 0, pb = 0;
+
+	/* r = m - x */
+	pb = 0;
+	pb += x[0]; b = lt_modm(modm_m[0], pb); r[0] = (modm_m[0] - pb + (b << 30)); pb = b;
+	pb += x[1]; b = lt_modm(modm_m[1], pb); r[1] = (modm_m[1] - pb + (b << 30)); pb = b;
+	pb += x[2]; b = lt_modm(modm_m[2], pb); r[2] = (modm_m[2] - pb + (b << 30)); pb = b;
+	pb += x[3]; b = lt_modm(modm_m[3], pb); r[3] = (modm_m[3] - pb + (b << 30)); pb = b;
+	pb += x[4]; b = lt_modm(modm_m[4], pb); r[4] = (modm_m[4] - pb + (b << 30)); pb = b;
+	pb += x[5]; b = lt_modm(modm_m[5], pb); r[5] = (modm_m[5] - pb + (b << 30)); pb = b;
+	pb += x[6]; b = lt_modm(modm_m[6], pb); r[6] = (modm_m[6] - pb + (b << 30)); pb = b;
+	pb += x[7]; b = lt_modm(modm_m[7], pb); r[7] = (modm_m[7] - pb + (b << 30)); pb = b;
+	pb += x[8]; b = lt_modm(modm_m[8], pb); r[8] = (modm_m[8] - pb + (b << 16));
+
+	// if x==0, reduction is required
+	reduce256_modm(r);
+}
+
+/* consts for subtraction, > p */
+/* Emilia Kasper trick, https://www.imperialviolet.org/2010/12/04/ecc.html */
+static const uint32_t twoP[] = {
+		0x5cf5d3ed, 0x60498c68, 0x6f79cd64, 0x77be77a7, 0x40000013, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0xfff};
+
+/* subtraction x-y % m */
+void sub256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) {
+	bignum256modm_element_t c = 0;
+	c  = twoP[0] + x[0] - y[0]; r[0] = c & 0x3fffffff; c >>= 30;
+	c += twoP[1] + x[1] - y[1]; r[1] = c & 0x3fffffff; c >>= 30;
+	c += twoP[2] + x[2] - y[2]; r[2] = c & 0x3fffffff; c >>= 30;
+	c += twoP[3] + x[3] - y[3]; r[3] = c & 0x3fffffff; c >>= 30;
+	c += twoP[4] + x[4] - y[4]; r[4] = c & 0x3fffffff; c >>= 30;
+	c += twoP[5] + x[5] - y[5]; r[5] = c & 0x3fffffff; c >>= 30;
+	c += twoP[6] + x[6] - y[6]; r[6] = c & 0x3fffffff; c >>= 30;
+	c += twoP[7] + x[7] - y[7]; r[7] = c & 0x3fffffff; c >>= 30;
+	c += twoP[8] + x[8] - y[8]; r[8] = c;
+	reduce256_modm(r);
+}
+
+/* multiplication modulo m */
+void mul256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) {
+	bignum256modm r1 = {0}, q1 = {0};
+	uint64_t c = 0;
+	bignum256modm_element_t f = 0;
+
+	/* r1 = (x mod 256^(32+1)) = x mod (2^8)(31+1) = x & ((1 << 264) - 1)
+	   q1 = x >> 248 = 264 bits = 9 30 bit elements */
+	c = mul32x32_64(x[0], y[0]);
+	f = (bignum256modm_element_t)c; r1[0] = (f & 0x3fffffff); c >>= 30;
+	c += mul32x32_64(x[0], y[1]) + mul32x32_64(x[1], y[0]);
+	f = (bignum256modm_element_t)c; r1[1] = (f & 0x3fffffff); c >>= 30;
+	c += mul32x32_64(x[0], y[2]) + mul32x32_64(x[1], y[1]) + mul32x32_64(x[2], y[0]);
+	f = (bignum256modm_element_t)c; r1[2] = (f & 0x3fffffff); c >>= 30;
+	c += mul32x32_64(x[0], y[3]) + mul32x32_64(x[1], y[2]) + mul32x32_64(x[2], y[1]) + mul32x32_64(x[3], y[0]);
+	f = (bignum256modm_element_t)c; r1[3] = (f & 0x3fffffff); c >>= 30;
+	c += mul32x32_64(x[0], y[4]) + mul32x32_64(x[1], y[3]) + mul32x32_64(x[2], y[2]) + mul32x32_64(x[3], y[1]) + mul32x32_64(x[4], y[0]);
+	f = (bignum256modm_element_t)c; r1[4] = (f & 0x3fffffff); c >>= 30;
+	c += mul32x32_64(x[0], y[5]) + mul32x32_64(x[1], y[4]) + mul32x32_64(x[2], y[3]) + mul32x32_64(x[3], y[2]) + mul32x32_64(x[4], y[1]) + mul32x32_64(x[5], y[0]);
+	f = (bignum256modm_element_t)c; r1[5] = (f & 0x3fffffff); c >>= 30;
+	c += mul32x32_64(x[0], y[6]) + mul32x32_64(x[1], y[5]) + mul32x32_64(x[2], y[4]) + mul32x32_64(x[3], y[3]) + mul32x32_64(x[4], y[2]) + mul32x32_64(x[5], y[1]) + mul32x32_64(x[6], y[0]);
+	f = (bignum256modm_element_t)c; r1[6] = (f & 0x3fffffff); c >>= 30;
+	c += mul32x32_64(x[0], y[7]) + mul32x32_64(x[1], y[6]) + mul32x32_64(x[2], y[5]) + mul32x32_64(x[3], y[4]) + mul32x32_64(x[4], y[3]) + mul32x32_64(x[5], y[2]) + mul32x32_64(x[6], y[1]) + mul32x32_64(x[7], y[0]);
+	f = (bignum256modm_element_t)c; r1[7] = (f & 0x3fffffff); c >>= 30;
+	c += mul32x32_64(x[0], y[8]) + mul32x32_64(x[1], y[7]) + mul32x32_64(x[2], y[6]) + mul32x32_64(x[3], y[5]) + mul32x32_64(x[4], y[4]) + mul32x32_64(x[5], y[3]) + mul32x32_64(x[6], y[2]) + mul32x32_64(x[7], y[1]) + mul32x32_64(x[8], y[0]);
+	f = (bignum256modm_element_t)c; r1[8] = (f & 0x00ffffff); q1[0] = (f >> 8) & 0x3fffff; c >>= 30;
+	c += mul32x32_64(x[1], y[8]) + mul32x32_64(x[2], y[7]) + mul32x32_64(x[3], y[6]) + mul32x32_64(x[4], y[5]) + mul32x32_64(x[5], y[4]) + mul32x32_64(x[6], y[3]) + mul32x32_64(x[7], y[2]) + mul32x32_64(x[8], y[1]);
+	f = (bignum256modm_element_t)c; q1[0] = (q1[0] | (f << 22)) & 0x3fffffff; q1[1] = (f >> 8) & 0x3fffff; c >>= 30;
+	c += mul32x32_64(x[2], y[8]) + mul32x32_64(x[3], y[7]) + mul32x32_64(x[4], y[6]) + mul32x32_64(x[5], y[5]) + mul32x32_64(x[6], y[4]) + mul32x32_64(x[7], y[3]) + mul32x32_64(x[8], y[2]);
+	f = (bignum256modm_element_t)c; q1[1] = (q1[1] | (f << 22)) & 0x3fffffff; q1[2] = (f >> 8) & 0x3fffff; c >>= 30;
+	c += mul32x32_64(x[3], y[8]) + mul32x32_64(x[4], y[7]) + mul32x32_64(x[5], y[6]) + mul32x32_64(x[6], y[5]) + mul32x32_64(x[7], y[4]) + mul32x32_64(x[8], y[3]);
+	f = (bignum256modm_element_t)c; q1[2] = (q1[2] | (f << 22)) & 0x3fffffff; q1[3] = (f >> 8) & 0x3fffff; c >>= 30;
+	c += mul32x32_64(x[4], y[8]) + mul32x32_64(x[5], y[7]) + mul32x32_64(x[6], y[6]) + mul32x32_64(x[7], y[5]) + mul32x32_64(x[8], y[4]);
+	f = (bignum256modm_element_t)c; q1[3] = (q1[3] | (f << 22)) & 0x3fffffff; q1[4] = (f >> 8) & 0x3fffff; c >>= 30;
+	c += mul32x32_64(x[5], y[8]) + mul32x32_64(x[6], y[7]) + mul32x32_64(x[7], y[6]) + mul32x32_64(x[8], y[5]);
+	f = (bignum256modm_element_t)c; q1[4] = (q1[4] | (f << 22)) & 0x3fffffff; q1[5] = (f >> 8) & 0x3fffff; c >>= 30;
+	c += mul32x32_64(x[6], y[8]) + mul32x32_64(x[7], y[7]) + mul32x32_64(x[8], y[6]);
+	f = (bignum256modm_element_t)c; q1[5] = (q1[5] | (f << 22)) & 0x3fffffff; q1[6] = (f >> 8) & 0x3fffff; c >>= 30;
+	c += mul32x32_64(x[7], y[8]) + mul32x32_64(x[8], y[7]);
+	f = (bignum256modm_element_t)c; q1[6] = (q1[6] | (f << 22)) & 0x3fffffff; q1[7] = (f >> 8) & 0x3fffff; c >>= 30;
+	c += mul32x32_64(x[8], y[8]);
+	f = (bignum256modm_element_t)c; q1[7] = (q1[7] | (f << 22)) & 0x3fffffff; q1[8] = (f >> 8) & 0x3fffff;
+
+	barrett_reduce256_modm(r, q1, r1);
+}
+
+void expand256_modm(bignum256modm out, const unsigned char *in, size_t len) {
+	unsigned char work[64] = {0};
+	bignum256modm_element_t x[16] = {0};
+	bignum256modm q1 = {0};
+
+	memcpy(work, in, len);
+	x[0] = U8TO32_LE(work +  0);
+	x[1] = U8TO32_LE(work +  4);
+	x[2] = U8TO32_LE(work +  8);
+	x[3] = U8TO32_LE(work + 12);
+	x[4] = U8TO32_LE(work + 16);
+	x[5] = U8TO32_LE(work + 20);
+	x[6] = U8TO32_LE(work + 24);
+	x[7] = U8TO32_LE(work + 28);
+	x[8] = U8TO32_LE(work + 32);
+	x[9] = U8TO32_LE(work + 36);
+	x[10] = U8TO32_LE(work + 40);
+	x[11] = U8TO32_LE(work + 44);
+	x[12] = U8TO32_LE(work + 48);
+	x[13] = U8TO32_LE(work + 52);
+	x[14] = U8TO32_LE(work + 56);
+	x[15] = U8TO32_LE(work + 60);
+
+	/* r1 = (x mod 256^(32+1)) = x mod (2^8)(31+1) = x & ((1 << 264) - 1) */
+	out[0] = (                         x[0]) & 0x3fffffff;
+	out[1] = ((x[ 0] >> 30) | (x[ 1] <<  2)) & 0x3fffffff;
+	out[2] = ((x[ 1] >> 28) | (x[ 2] <<  4)) & 0x3fffffff;
+	out[3] = ((x[ 2] >> 26) | (x[ 3] <<  6)) & 0x3fffffff;
+	out[4] = ((x[ 3] >> 24) | (x[ 4] <<  8)) & 0x3fffffff;
+	out[5] = ((x[ 4] >> 22) | (x[ 5] << 10)) & 0x3fffffff;
+	out[6] = ((x[ 5] >> 20) | (x[ 6] << 12)) & 0x3fffffff;
+	out[7] = ((x[ 6] >> 18) | (x[ 7] << 14)) & 0x3fffffff;
+	out[8] = ((x[ 7] >> 16) | (x[ 8] << 16)) & 0x00ffffff;
+
+	/* 8*31 = 248 bits, no need to reduce */
+	if (len < 32)
+		return;
+
+	/* q1 = x >> 248 = 264 bits = 9 30 bit elements */
+	q1[0] = ((x[ 7] >> 24) | (x[ 8] <<  8)) & 0x3fffffff;
+	q1[1] = ((x[ 8] >> 22) | (x[ 9] << 10)) & 0x3fffffff;
+	q1[2] = ((x[ 9] >> 20) | (x[10] << 12)) & 0x3fffffff;
+	q1[3] = ((x[10] >> 18) | (x[11] << 14)) & 0x3fffffff;
+	q1[4] = ((x[11] >> 16) | (x[12] << 16)) & 0x3fffffff;
+	q1[5] = ((x[12] >> 14) | (x[13] << 18)) & 0x3fffffff;
+	q1[6] = ((x[13] >> 12) | (x[14] << 20)) & 0x3fffffff;
+	q1[7] = ((x[14] >> 10) | (x[15] << 22)) & 0x3fffffff;
+	q1[8] = ((x[15] >>  8)                );
+
+	barrett_reduce256_modm(out, q1, out);
+}
+
+void expand_raw256_modm(bignum256modm out, const unsigned char in[32]) {
+	bignum256modm_element_t x[8] = {0};
+
+	x[0] = U8TO32_LE(in +  0);
+	x[1] = U8TO32_LE(in +  4);
+	x[2] = U8TO32_LE(in +  8);
+	x[3] = U8TO32_LE(in + 12);
+	x[4] = U8TO32_LE(in + 16);
+	x[5] = U8TO32_LE(in + 20);
+	x[6] = U8TO32_LE(in + 24);
+	x[7] = U8TO32_LE(in + 28);
+
+	out[0] = (                         x[0]) & 0x3fffffff;
+	out[1] = ((x[ 0] >> 30) | (x[ 1] <<  2)) & 0x3fffffff;
+	out[2] = ((x[ 1] >> 28) | (x[ 2] <<  4)) & 0x3fffffff;
+	out[3] = ((x[ 2] >> 26) | (x[ 3] <<  6)) & 0x3fffffff;
+	out[4] = ((x[ 3] >> 24) | (x[ 4] <<  8)) & 0x3fffffff;
+	out[5] = ((x[ 4] >> 22) | (x[ 5] << 10)) & 0x3fffffff;
+	out[6] = ((x[ 5] >> 20) | (x[ 6] << 12)) & 0x3fffffff;
+	out[7] = ((x[ 6] >> 18) | (x[ 7] << 14)) & 0x3fffffff;
+	out[8] = ((x[ 7] >> 16)                ) & 0x0000ffff;
+}
+
+int is_reduced256_modm(const bignum256modm in)
+{
+	int i = 0;
+	uint32_t res1 = 0;
+	uint32_t res2 = 0;
+	for (i = 8; i >= 0; i--) {
+		res1 = (res1 << 1) | (in[i] < modm_m[i]);
+		res2 = (res2 << 1) | (in[i] > modm_m[i]);
+	}
+	return res1 > res2;
+}
+
+void contract256_modm(unsigned char out[32], const bignum256modm in) {
+	U32TO8_LE(out +  0, (in[0]      ) | (in[1] << 30));
+	U32TO8_LE(out +  4, (in[1] >>  2) | (in[2] << 28));
+	U32TO8_LE(out +  8, (in[2] >>  4) | (in[3] << 26));
+	U32TO8_LE(out + 12, (in[3] >>  6) | (in[4] << 24));
+	U32TO8_LE(out + 16, (in[4] >>  8) | (in[5] << 22));
+	U32TO8_LE(out + 20, (in[5] >> 10) | (in[6] << 20));
+	U32TO8_LE(out + 24, (in[6] >> 12) | (in[7] << 18));
+	U32TO8_LE(out + 28, (in[7] >> 14) | (in[8] << 16));
+}
+
+void contract256_window4_modm(signed char r[64], const bignum256modm in) {
+	char carry = 0;
+	signed char *quads = r;
+	bignum256modm_element_t i = 0, j = 0, v = 0;
+
+	for (i = 0; i < 8; i += 2) {
+		v = in[i];
+		for (j = 0; j < 7; j++) {
+			*quads++ = (v & 15);
+			v >>= 4;
+		}
+		v |= (in[i+1] << 2);
+		for (j = 0; j < 8; j++) {
+			*quads++ = (v & 15);
+			v >>= 4;
+		}
+	}
+	v = in[8];
+	*quads++ = (v & 15); v >>= 4;
+	*quads++ = (v & 15); v >>= 4;
+	*quads++ = (v & 15); v >>= 4;
+	*quads++ = (v & 15); v >>= 4;
+
+	/* making it signed */
+	carry = 0;
+	for(i = 0; i < 63; i++) {
+		r[i] += carry;
+		r[i+1] += (r[i] >> 4);
+		r[i] &= 15;
+		carry = (r[i] >> 3);
+		r[i] -= (carry << 4);
+	}
+	r[63] += carry;
+}
+
+void contract256_slidingwindow_modm(signed char r[256], const bignum256modm s, int windowsize) {
+	int i = 0, j = 0, k = 0, b = 0;
+	int m = (1 << (windowsize - 1)) - 1, soplen = 256;
+	signed char *bits = r;
+	bignum256modm_element_t v = 0;
+
+	/* first put the binary expansion into r  */
+	for (i = 0; i < 8; i++) {
+		v = s[i];
+		for (j = 0; j < 30; j++, v >>= 1)
+			*bits++ = (v & 1);
+	}
+	v = s[8];
+	for (j = 0; j < 16; j++, v >>= 1)
+		*bits++ = (v & 1);
+
+	/* Making it sliding window */
+	for (j = 0; j < soplen; j++) {
+		if (!r[j])
+			continue;
+
+		for (b = 1; (b < (soplen - j)) && (b <= 6); b++) {
+			if ((r[j] + (r[j + b] << b)) <= m) {
+				r[j] += r[j + b] << b;
+				r[j + b] = 0;
+			} else if ((r[j] - (r[j + b] << b)) >= -m) {
+				r[j] -= r[j + b] << b;
+				for (k = j + b; k < soplen; k++) {
+					if (!r[k]) {
+						r[k] = 1;
+						break;
+					}
+					r[k] = 0;
+				}
+			} else if (r[j + b]) {
+				break;
+			}
+		}
+	}
+}
+
+void set256_modm(bignum256modm r, uint64_t v) {
+	r[0] = (bignum256modm_element_t) (v & 0x3fffffff); v >>= 30;
+	r[1] = (bignum256modm_element_t) (v & 0x3fffffff); v >>= 30;
+	r[2] = (bignum256modm_element_t) (v & 0x3fffffff);
+	r[3] = 0;
+	r[4] = 0;
+	r[5] = 0;
+	r[6] = 0;
+	r[7] = 0;
+	r[8] = 0;
+}
+
+int get256_modm(uint64_t * v, const bignum256modm r){
+	*v = 0;
+	int con1 = 0;
+
+#define NONZ(x) ((((((int64_t)(x)) - 1) >> 32) + 1) & 1)
+	bignum256modm_element_t c = 0;
+	c  = r[0];  *v +=  (uint64_t)c & 0x3fffffff;        c >>= 30; // 30
+	c += r[1];  *v += ((uint64_t)c & 0x3fffffff) << 30; c >>= 30; // 60
+	c += r[2];  *v += ((uint64_t)c & 0xf)        << 60; con1 |= NONZ(c>>4); c >>= 30; // 64 bits
+	c += r[3];                                          con1 |= NONZ(c); c >>= 30;
+	c += r[4];                                          con1 |= NONZ(c); c >>= 30;
+	c += r[5];                                          con1 |= NONZ(c); c >>= 30;
+	c += r[6];                                          con1 |= NONZ(c); c >>= 30;
+	c += r[7];                                          con1 |= NONZ(c); c >>= 30;
+	c += r[8];                                          con1 |= NONZ(c); c >>= 30;
+	                                                    con1 |= NONZ(c);
+#undef NONZ
+
+	return con1 ^ 1;
+}
+
+int eq256_modm(const bignum256modm x, const bignum256modm y){
+	size_t differentbits = 0;
+	int len = bignum256modm_limb_size;
+	while (len--) {
+		differentbits |= (*x++ ^ *y++);
+	}
+	return (int) (1 & ((differentbits - 1) >> bignum256modm_bits_per_limb));
+}
+
+int cmp256_modm(const bignum256modm x, const bignum256modm y){
+	int len = 2*bignum256modm_limb_size;
+	uint32_t a_gt = 0;
+	uint32_t b_gt = 0;
+
+	// 16B chunks
+	while (len--) {
+		const uint32_t ln = (const uint32_t) len;
+		const uint32_t a = (x[ln>>1] >> 16*(ln & 1)) & 0xffff;
+		const uint32_t b = (y[ln>>1] >> 16*(ln & 1)) & 0xffff;
+
+		const uint32_t limb_a_gt = ((b - a) >> 16) & 1;
+		const uint32_t limb_b_gt = ((a - b) >> 16) & 1;
+		a_gt |= limb_a_gt & ~b_gt;
+		b_gt |= limb_b_gt & ~a_gt;
+	}
+
+	return a_gt - b_gt;
+}
+
+int iszero256_modm(const bignum256modm x){
+	size_t differentbits = 0;
+	int len = bignum256modm_limb_size;
+	while (len--) {
+		differentbits |= (*x++);
+	}
+	return (int) (1 & ((differentbits - 1) >> bignum256modm_bits_per_limb));
+}
+
+void copy256_modm(bignum256modm r, const bignum256modm x){
+	r[0] = x[0];
+	r[1] = x[1];
+	r[2] = x[2];
+	r[3] = x[3];
+	r[4] = x[4];
+	r[5] = x[5];
+	r[6] = x[6];
+	r[7] = x[7];
+	r[8] = x[8];
+}
+
+int check256_modm(const bignum256modm x){
+	int ok = 1;
+	bignum256modm t={0}, z={0};
+
+	ok &= iszero256_modm(x) ^ 1;
+	barrett_reduce256_modm(t, z, x);
+	ok &= eq256_modm(t, x);
+	return ok;
+}
+
+void mulsub256_modm(bignum256modm r, const bignum256modm a, const bignum256modm b, const bignum256modm c){
+	//(cc - aa * bb) % l
+	bignum256modm t={0};
+	mul256_modm(t, a, b);
+	sub256_modm(r, c, t);
+}
+
+void muladd256_modm(bignum256modm r, const bignum256modm a, const bignum256modm b, const bignum256modm c){
+	//(cc + aa * bb) % l
+	bignum256modm t={0};
+	mul256_modm(t, a, b);
+	add256_modm(r, c, t);
+}

+ 80 - 0
crypto/ed25519-donna/modm-donna-32bit.h

@@ -0,0 +1,80 @@
+/*
+	Public domain by Andrew M. <liquidsun@gmail.com>
+*/
+
+
+/*
+	Arithmetic modulo the group order n = 2^252 +  27742317777372353535851937790883648493 = 7237005577332262213973186563042994240857116359379907606001950938285454250989
+
+	k = 32
+	b = 1 << 8 = 256
+	m = 2^252 + 27742317777372353535851937790883648493 = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed
+	mu = floor( b^(k*2) / m ) = 0xfffffffffffffffffffffffffffffffeb2106215d086329a7ed9ce5a30a2c131b
+*/
+
+#define bignum256modm_bits_per_limb 30
+#define bignum256modm_limb_size 9
+
+typedef uint32_t bignum256modm_element_t;
+typedef bignum256modm_element_t bignum256modm[9];
+
+/* see HAC, Alg. 14.42 Step 4 */
+void reduce256_modm(bignum256modm r);
+
+/*
+	Barrett reduction,  see HAC, Alg. 14.42
+
+	Instead of passing in x, pre-process in to q1 and r1 for efficiency
+*/
+void barrett_reduce256_modm(bignum256modm r, const bignum256modm q1, const bignum256modm r1);
+
+/* addition modulo m */
+void add256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y);
+
+/* -x modulo m */
+void neg256_modm(bignum256modm r, const bignum256modm x);
+
+/* subtraction x-y modulo m */
+void sub256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y);
+
+/* multiplication modulo m */
+void mul256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y);
+
+void expand256_modm(bignum256modm out, const unsigned char *in, size_t len);
+
+void expand_raw256_modm(bignum256modm out, const unsigned char in[32]);
+
+int is_reduced256_modm(const bignum256modm in);
+
+void contract256_modm(unsigned char out[32], const bignum256modm in);
+
+void contract256_window4_modm(signed char r[64], const bignum256modm in);
+
+void contract256_slidingwindow_modm(signed char r[256], const bignum256modm s, int windowsize);
+
+/* 64bit uint to scalar value */
+void set256_modm(bignum256modm r, uint64_t v);
+
+/* scalar value to 64bit uint */
+int get256_modm(uint64_t * v, const bignum256modm r);
+
+/* equality test on two reduced scalar values */
+int eq256_modm(const bignum256modm x, const bignum256modm y);
+
+/* comparison of two reduced scalar values */
+int cmp256_modm(const bignum256modm x, const bignum256modm y);
+
+/* scalar null check, has to be reduced */
+int iszero256_modm(const bignum256modm x);
+
+/* simple copy, no reduction */
+void copy256_modm(bignum256modm r, const bignum256modm x);
+
+/* check if nonzero && same after reduction */
+int check256_modm(const bignum256modm x);
+
+/* (cc - aa * bb) % l */
+void mulsub256_modm(bignum256modm r, const bignum256modm a, const bignum256modm b, const bignum256modm c);
+
+/* (cc + aa * bb) % l */
+void muladd256_modm(bignum256modm r, const bignum256modm a, const bignum256modm b, const bignum256modm c);

+ 105 - 0
crypto/fuzzer/README.md

@@ -0,0 +1,105 @@
+# Fuzz Testing trezor-crypto
+Selected functions can be fuzzed via specific libFuzzer harnesses for increased test coverage and issue detection.
+
+Note: the following commands are relative to the trezor-crypto main directory.
+
+## Build
+
+A modern C compiler with built-in libFuzzer support is required. The build process will use `clang` by default.
+Set the `CC=` environment variable if you want to use a special compiler variant.
+
+```bash
+make clean
+FUZZER=1 make fuzzer -j$(nproc)
+```
+
+### Sanitizers
+Recommended: ASAN / UBSAN / MSAN flags for error detection can be specified via the special `SANFLAGS`.
+
+Examples:
+
+* `SANFLAGS="-fsanitize=address,undefined"`
+* `SANFLAGS="-fsanitize=memory -fsanitize-memory-track-origins"`
+
+### Optimizations
+
+Override `OPTFLAGS` to test the library at different optimization levels or simplify the debugging of detected issues.
+
+Examples:
+
+* `OPTFLAGS="-O0 -ggdb3"`
+* `OPTFLAGS="-O3 -march=native -fno-omit-frame-pointer -gline-tables-only"`
+
+To be determined:
+
+* semi-automatic use of `-fsanitize-ignorelist` to reduce sanitizer overhead on hot functions
+* `-flto` and `-flto=thin` link time optimization
+
+Advanced usage:
+* [Profile guided optimization](https://clang.llvm.org/docs/UsersManual.html#profile-guided-optimization)
+
+### Fuzzer-specific Configuration Flags
+
+* `-DFUZZ_ALLOW_SLOW` to enable optional fuzzing targets of slow functions
+* select a specific fuzz testing harness with `-DFUZZER_EXCLUSIVE_TARGET=` to disable the use of all other targets
+
+### Other Flags
+
+To be determined:
+
+* `-DNDEBUG`
+* `-DUSE_BIP39_CACHE=0 -DUSE_BIP32_CACHE=0` to explicitly disable the cache, a workaround for automatic cache clearing is used otherwise
+* `-D_FORTIFY_SOURCE=2` together with optimization flag -O2 or above
+* `-fstack-protector-strong` or `-fstack-protector-all`
+* `-m32` to closer emulate the 32-bit environment present on microcontroller platforms
+    * manually adjust Makefile `DSECP256K1_CONTEXT_SIZE=` for 32-bit values, see `legacy/firmware/Makefile`
+    * this flag requires 32-bit build support for gcc-multilib, libc and others
+    * switching from 64-bit to 32-bit has some effects on sanitizer internals such as Address Sanitizer
+* `-DSHA2_UNROLL_TRANSFORM` SHA2 optimization flags
+* `-fsanitize-coverage=edge,trace-cmp,trace-div,indirect-calls,trace-gep,no-prune` to add program counter granularity
+* starting with clang-15, the additional `trace-loads` and `trace-stores` sanitizer coverage options are also available
+
+## Operation
+
+See the [libFuzzer documentation](https://llvm.org/docs/LibFuzzer.html#options) for valid options and usage. Detailed fuzzer usage and relevant considerations are out of scope of this document.
+
+**Warning**: fuzzing is resource-intensive and can have a negative impact on your system stability.
+
+Basic fuzzer call:
+```bash
+./fuzzer/fuzzer
+```
+
+Here is a more sophisticated multithreading example with a persistent input corpus and other optimizations:
+```bash
+mkdir fuzzer/fuzzer_corpus
+./fuzzer/fuzzer -max_len=2048 -use_value_profile=1 -workers=16 -jobs=16 -timeout=1 -reload=5 -print_pcs=1 -print_funcs=42  fuzzer/fuzzer_corpus
+```
+
+Hint: for more permanent setups, consider invoking the fuzzer from outside of the source directory to avoid cluttering it with logfiles and crash inputs. Similarly, it is recommended to store the fuzzer corpus in another location.
+
+## Automated Fuzzer Dictionary Generation
+
+[Dictionaries](https://llvm.org/docs/LibFuzzer.html#dictionaries) are a useful mechanism to augment the capabilities of the fuzzer. Specify them via the `-dict=` flag.
+
+### Collect Interesting Strings From Unit Tests
+
+```bash
+cd fuzzer
+./extract_fuzzer_dictionary.sh fuzzer_crypto_tests_strings_dictionary1.txt
+```
+The resulting file can be used as a fuzzer dictionary.
+
+## Evaluate Source Coverage
+
+  1. build the fuzzer binary with `CFLAGS="-fprofile-instr-generate -fcoverage-mapping"`
+  1. run with suitable `-runs=` or `-max_total_time=` limits
+  1. convert the recorded data `llvm-profdata merge -output=default.profdata -instr default.profraw`
+  1. render the data `llvm-cov show fuzzer/fuzzer -instr-profile=default.profdata -format=html -output-dir=coverage-report`
+  1. analyze report at `coverage-report/index.html`
+  1. (optional) remove artifacts with `rm default.profraw default.profdata && rm -r coverage-report`
+
+## Using Honggfuzz Fuzzer
+
+Although this code is designed primarily for libFuzzer, it can also be used with [Honggfuzz](https://honggfuzz.dev).
+However, the usage details are out of scope of this document.

+ 399 - 0
crypto/fuzzer/extract_fuzzer_dictionary.py

@@ -0,0 +1,399 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+This experimental program is designed to extract a subset of interesting test
+case snippets from the trezor-crypto test directory and output them as a
+standard fuzzer dictionary file.
+
+The program is built on quick-and-dirty regex matching that is known to be
+incorrect for parsing code files, but is considered "good enough" for this
+specific purpose.
+Note that there are target-specific configurations and internal filter settings.
+"""
+
+import argparse
+import binascii
+import glob
+import re
+
+# re2 is considered for future use
+# it requires a system installation and the google-re2 python package
+# import re2
+
+
+# Expected target format for strings in code:
+# Most strings are defined in the general form "example"
+# There are a few test vectors in crypto/tests/wycheproof/javascript/EcUtil.js
+# with 'example' style string definitions, these are ignored for now
+
+TARGET_DIR = "../tests"
+
+# intentionally excluded file types that currently do not provide enough value:
+# *.js, *.md, *.sh, *.html and others from the wycheproof subdirectory
+
+targeted_filetypes_multiline_classA = ("*.c", "*.h", "*.py")
+# Java files have different multiline strings that are handled differently
+targeted_filetypes_multiline_classB = ("*.java",)
+targeted_filetypes_multiline = (
+    targeted_filetypes_multiline_classA + targeted_filetypes_multiline_classB
+)
+
+# files without multiline string content
+# Note: consider switching to actual JSON parsing?
+# Note: the wycheproof repository has a number of test cases for other
+# cryptography such as DSA and RSA which are currently less interesting for the
+# fuzzer dictionary and therefore excluded
+targeted_filetypes_singleline = (
+    "aes*.json",
+    "ecdh*.json",
+    "ecdsa*.json",
+    "x25519*.json",
+    "chacha20*.json",
+    "kw*.json",
+)
+
+verbose = False
+
+# patterns to extract
+# singleline:
+# "4a1e76f133afb"
+# 0xAF8BBDFE8CDD5 and 0x0488b21e
+# m/0'/2147483647'/1'/2147483646'/2' in test_check.c via m/[\d'/]+
+#
+# multiline:
+# "fffc" \n "99"
+# "dpubZ9169K" \n "bTYbcY"
+# "\x65\xf9" \\n  "\xa0\x6a"
+# { 0x086d8bd5, 0x1018f82f, \n 0xc55ece} , see rg "0x([a-zA-Z0-9])+"
+
+# patterns to ignore
+# lines with print statements
+# lines with exceptions
+# comments and other metadata in the testvector JSON files
+# filenames
+# import statements and other package names
+
+# patterns to investigate further
+# public keys with the form BEGIN PUBLIC KEY
+# TODO "abc" + "def" string concatenation on the same line without newline
+# strings in comments
+
+# dictionary text export file format
+# general description:
+# https://github.com/AFLplusplus/AFLplusplus/blob/stable/dictionaries/README.md
+#
+# the exported file is primarly designed for use with a recent libFuzzer version
+# and is known to be partially incompatible with other fuzzers that impose
+# other limitations
+#
+# known incompatibilities:
+# * honggfuzz only reads a limited number of dictionary entries (8192 with version 2.5)
+# * afl++ only reads line content with up to 128 byte
+
+# match everything in quotes that doesn't have an internal quote character and
+# at least one internal character
+regex_string_general_definition = r"\"[^\"]+\""
+regex_string_general = re.compile(regex_string_general_definition)
+# the capturing group ignores prefix and suffix outside of the quotes
+# Note that this is prone to matching the last line of a C-style multiline string,
+# which is addressed via extra state handling during the file processing
+regex_oneline_string = re.compile(
+    r"(" + regex_string_general_definition + r")\s*[\,\)]+"
+)
+# ignore lines that have a "+" character preceding a string
+regex_oneline_string_java_ignore1 = re.compile(r"^\s*\+\s*\"")
+
+regex_hex_character_segment_inner_definition = "[0-9a-fA-F]+"
+regex_hex_character_input_complete = re.compile(
+    '^"' + regex_hex_character_segment_inner_definition + '"$'
+)
+regex_hex_character_input_inner = re.compile(
+    regex_hex_character_segment_inner_definition
+)
+# most constants are preceded by a space, but some have a "(" "[" or "{" before them
+regex_hex_constant_singleline = re.compile(r"(?<=\(|\[|\{| )0x[a-fA-F0-9]+")
+
+regex_c_style_multiline = re.compile(r"(?:\".+\"\s*\n\s*)+(?:\".+\")", re.MULTILINE)
+regex_c_intermediary_content = re.compile(r"\"\s*\n\s*\"", re.MULTILINE)
+# TODO how to prevent matching in the middle of a multi-line string concatenation?
+# negative lookbehind for "+" is not possible generically and
+# (?<!\+ ) and similar patterns are too static
+
+regex_java_style_multiline = re.compile(
+    r"(?:\".+\"\s*\n\s*\+\s*)+(?:\".+\")", re.MULTILINE
+)
+regex_java_intermediary_content = re.compile(r"\"\s*\n\s*\+\s*\"", re.MULTILINE)
+
+regex_text_newline = re.compile(r"\\n")
+
+# primitive regex that catches most filenames in the data set
+regex_filename_heuristic = re.compile(r"\.[a-zA-Z]+")
+
+counter_hex_content = 0
+counter_wycheproof_hex_reconstruction = 0
+
+# TODO add '"curve"' to capture algorithm names?
+allowlist_keywords_json = (
+    '"uncompressed"',
+    '"wx"',
+    '"wy"',
+    '"msg"',
+    '"sig"',
+    '"key"',
+    '"iv"',
+    '"ct"',
+    '"aad"',
+    '"tag"',
+    '"public"',
+    '"private"',
+    '"shared"',
+    '"padding"',
+    '"x"',
+    '"d"',
+)
+
+# TODO the "keyPem" entry is only a workaround for an encoding issue
+ignore_keywords_java = (
+    "println(",
+    "Exception(",
+    '"keyPem"',
+)
+ignore_keywords_c = ("printf(",)
+
+
+def ignore_single_line_json(data):
+    """return True if the input should be ignored"""
+    # ignore everything that is not matched by the allowlist
+    for keyword in allowlist_keywords_json:
+        if data.find(keyword) > -1:
+            return False
+    return True
+
+
+def ignore_single_line_java(data):
+    """return True if the input should be ignored"""
+    for keyword in ignore_keywords_java:
+        if data.find(keyword) > -1:
+            return True
+    return False
+
+
+def ignore_single_line_c(data):
+    """return True if the input should be ignored"""
+    for keyword in ignore_keywords_c:
+        if data.find(keyword) > -1:
+            return True
+    return False
+
+
+def ignore_general(data):
+    """return True if the input should be ignored"""
+    if regex_filename_heuristic.search(data):
+        return True
+    return False
+
+
+def encode_strings_for_dictionary(data):
+    """
+    Assumes that inputs are already in string quotes
+
+    Handles dictionary-specific encoding steps
+    """
+    # libfuzzer does not like "\n" string patterns in dictionary files, replace
+    # it with an encoded newline
+    data = regex_text_newline.sub("\\\\x0a", data)
+    return data
+
+
+def detect_and_convert_hex(data):
+    """
+    Convert hex strings
+
+    Directly pass through non-hex content
+    """
+    global counter_hex_content
+    global counter_wycheproof_hex_reconstruction
+    match_result1 = regex_hex_character_input_complete.search(data)
+    if match_result1:
+
+        match_result2 = regex_hex_character_input_inner.search(match_result1.string)
+        isolated_substring = match_result2.group(0)
+        if len(isolated_substring) % 2 == 1:
+            # Note: the test cases in the wycheproof testvector JSON files have
+            # a custom binary hex format to represent keys
+            # among other things, this results in hex strings with an uneven
+            # number of characters
+            # see tests/wycheproof/java/com/google/security/wycheproof/JsonUtil.java
+            # specifically the asBigInteger() function for more information
+            if isolated_substring[0] >= "0" and isolated_substring[0] <= "7":
+                isolated_substring = "0" + isolated_substring
+            else:
+                isolated_substring = "f" + isolated_substring
+            counter_wycheproof_hex_reconstruction += 1
+
+        converted_result = ""
+        try:
+            # test error-free conversion to binary
+            binascii.unhexlify(isolated_substring)
+            hex_with_c_style_formatting = ""
+            pos = 0
+            while pos < len(isolated_substring) - 1:
+                hex_with_c_style_formatting += "\\x" + isolated_substring[pos : pos + 2]
+                pos += 2
+
+            converted_result = '"%s"' % hex_with_c_style_formatting
+        # TODO binascii.Incomplete exception also relevant?
+        except binascii.Error:
+            # default to the original input
+            return data
+        counter_hex_content += 1
+        return converted_result
+    return data
+
+
+def search_files_recursively(directory, filetype_glob):
+    """returns glob search results"""
+    target_files = []
+    print_verbose("searching in %s" % directory)
+    for filetype in filetype_glob:
+        print_verbose("searching for %s" % filetype)
+        target_files.extend(glob.glob(f"{directory}/**/{filetype}", recursive=True))
+    return target_files
+
+
+def print_verbose(text):
+    """print wrapper"""
+    if verbose:
+        print(text)
+
+
+def recursive_dictionary_extraction(directory):
+    """handle the central extraction logic"""
+    # TODO split this function up into subfunctions
+    global counter_hex_content
+    # handle as a set structure to de-duplicate results automatically
+    candidate_lines = set()
+
+    target_files = search_files_recursively(directory, targeted_filetypes_singleline)
+    for filepath in target_files:
+        per_file_result_counter = 0
+        with open(filepath) as _file:
+            print_verbose("processing %s" % filepath)
+            for _, line in enumerate(_file.readlines()):
+                if ignore_single_line_json(line):
+                    continue
+                results = regex_oneline_string.findall(line)
+                for result in results:
+                    candidate_lines.add(result)
+                    per_file_result_counter += 1
+            if per_file_result_counter > 0:
+                print_verbose("results: %d" % per_file_result_counter)
+
+    print_verbose("number of candidate entries: %d" % len(candidate_lines))
+
+    target_files = search_files_recursively(directory, targeted_filetypes_multiline)
+    for filepath in target_files:
+        per_file_result_counter = 0
+        with open(filepath) as _file:
+            last_line_was_multiline_string = False
+            print_verbose("processing %s for single-line strings" % filepath)
+            for _, line in enumerate(_file.readlines()):
+                if ignore_single_line_java(line):
+                    last_line_was_multiline_string = False
+                    continue
+                if ignore_single_line_c(line):
+                    last_line_was_multiline_string = False
+                    continue
+                if regex_oneline_string_java_ignore1.search(line):
+                    last_line_was_multiline_string = True
+                    if regex_oneline_string.search(line):
+                        # the Java multiline string apparently ends on this line
+                        last_line_was_multiline_string = False
+                    continue
+
+                result_general_string = regex_string_general.search(line)
+                if result_general_string:
+                    # at least one general string is matched, see if it is
+                    # a single-line string
+                    results = regex_oneline_string.findall(line)
+                    for result in results:
+                        if not last_line_was_multiline_string:
+                            candidate_lines.add(result)
+                            per_file_result_counter += 1
+                        last_line_was_multiline_string = False
+                    if len(results) == 0:
+                        last_line_was_multiline_string = True
+                else:
+                    last_line_was_multiline_string = False
+
+                # TODO split this into a separate loop?
+                results = regex_hex_constant_singleline.findall(line)
+                for result in results:
+                    # remove the "0x" prefix, add quotes
+                    candidate_lines.add('"%s"' % result[2:])
+                    per_file_result_counter += 1
+
+            if per_file_result_counter > 0:
+                print_verbose("results: %d" % per_file_result_counter)
+
+    target_files = search_files_recursively(
+        directory, targeted_filetypes_multiline_classA
+    )
+
+    for filepath in target_files:
+        with open(filepath) as _file:
+            print_verbose("processing %s for C-style multi-line strings" % filepath)
+            filecontent = _file.read()
+            multiline_results = regex_c_style_multiline.findall(filecontent)
+            if len(multiline_results) > 0:
+                print_verbose("results: %d" % len(multiline_results))
+            for result in multiline_results:
+                cleanup = regex_c_intermediary_content.sub("", result)
+                candidate_lines.add(cleanup)
+
+    target_files = search_files_recursively(
+        directory, targeted_filetypes_multiline_classB
+    )
+
+    for filepath in target_files:
+        with open(filepath) as _file:
+            print_verbose("processing %s for Java-style multi-line strings" % filepath)
+            filecontent = _file.read()
+            multiline_results = regex_java_style_multiline.findall(filecontent)
+            if len(multiline_results) > 0:
+                print_verbose("results: %d" % len(multiline_results))
+            for result in multiline_results:
+                cleanup = regex_java_intermediary_content.sub("", result)
+                candidate_lines.add(cleanup)
+
+    return candidate_lines
+
+
+if __name__ == "__main__":
+    parser = argparse.ArgumentParser()
+    parser.add_argument("dictionary_output_file", help="output file", type=str)
+    parser.add_argument("--verbose", action="store_true", help="verbose stdout output")
+
+    args = parser.parse_args()
+    verbose = args.verbose
+
+    collected_candidate_lines = recursive_dictionary_extraction(TARGET_DIR)
+    sorted_candidate_lines = sorted(collected_candidate_lines)
+    result_lines = []
+    for candidate_line in sorted_candidate_lines:
+        if ignore_general(candidate_line):
+            continue
+        result_lines.append(
+            encode_strings_for_dictionary(detect_and_convert_hex(candidate_line))
+        )
+
+    print_verbose("counter_hex_content: %d" % counter_hex_content)
+    print_verbose(
+        "counter_wycheproof_hex_reconstruction: %d"
+        % counter_wycheproof_hex_reconstruction
+    )
+    print_verbose("overall deduplicated entries: %d" % len(sorted_candidate_lines))
+
+    with open(args.dictionary_output_file, "w") as _file:
+        for result_line in result_lines:
+            _file.write("%s\n" % result_line)

+ 49 - 0
crypto/fuzzer/extract_fuzzer_dictionary.sh

@@ -0,0 +1,49 @@
+#!/usr/bin/env bash
+
+# usage: script.sh target-dictionary-filename
+
+# This script searches for interesting strings in the source code and converts
+# them into a standard fuzzer dictionary file.
+#
+# Note that this script is phased out in favor of the more sophisticated
+# extract_fuzzer_dictionary.py program
+
+# TODO known issues: the end result has some duplicates in it
+
+TARGET_DIR=../tests
+OUTPUT_FILE=${1:-fuzzer_crypto_tests_strings_dictionary1.txt}
+
+multiline_string_search() {
+  # TODO the `find` regex behavior is Linux-specific
+  find $TARGET_DIR -type f -regextype posix-extended -regex '.*\.(c|h|py|json|java|js)' | xargs cat | perl -p0e 's/"\s*\n\s*\"//smg'
+}
+
+# ensure empty file
+echo -n "" > $OUTPUT_FILE
+
+# strip multiline strings and extract them
+# exclude some hex strings, but allow hex strings with mixed capitalization (Ethereum, rskip60)
+multiline_string_search | grep -P -o  "\"[\w ]+\"" | grep -v -P "\"(([0-9a-f][0-9a-f])+|([0-9A-F][0-9A-F])+)\"" | sort | uniq | while read -r line ; do
+  echo "$line" >> $OUTPUT_FILE
+done
+
+# extract individual BIP39 and SLIP39 words
+# TODO are those actually valuable as fuzzer dictionary input?
+# grep -r -P -o -h "\"\w+\""  ../slip39_wordlist.h ../bip39_english.h | sort | uniq >> fuzzer_crypto_tests_strings_dictionary1.txt
+
+# extract and convert binary input data from the unit tests
+# find each file, cat it, concatenate multiline strings, look for hex strings in quotes
+# note that this returns multiple megabyte of result strings due to the large amount
+# of test cases in the wycheproof project subfolder
+multiline_string_search | grep -P -o "\"([0-9a-fA-F][0-9a-fA-F])+\"" | grep -P -o "([0-9a-fA-F][0-9a-fA-F])+" | sort | uniq | while read -r line ; do
+  # turn ascii hex strings AA into \xaa for the fuzzer format and add quotes
+  # extra backslash escape due to the bash nesting
+  escaped_hex=`echo $line | sed -e 's/../\\\\x&/g'`
+  echo "\"$escaped_hex\"" >> $OUTPUT_FILE
+done
+
+# search and reassemble BIP39 test seeds that span multiple lines
+# find each file, cat it, concatenate multiline strings, look for BIP39 seed combinations with reasonable length
+multiline_string_search | grep -Po "(\w{3,10} ){11,23}(\w{3,10})" | sort | uniq | while read -r line ; do
+  echo "\"$line\"" >> $OUTPUT_FILE
+done

+ 1616 - 0
crypto/fuzzer/fuzzer.c

@@ -0,0 +1,1616 @@
+/**
+ * Copyright (c) 2020-2022 Christian Reitter
+ *
+ * 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 <math.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+// includes for potential target functions
+// based on test_check.c
+#include "address.h"
+#include "aes/aes.h"
+#include "base32.h"
+#include "base58.h"
+#include "bignum.h"
+#include "bip32.h"
+#include "bip39.h"
+#include "blake256.h"
+#include "blake2b.h"
+#include "blake2s.h"
+#include "chacha_drbg.h"
+#include "curves.h"
+#include "ecdsa.h"
+#include "ed25519-donna/ed25519-donna.h"
+#include "ed25519-donna/ed25519-keccak.h"
+#include "ed25519-donna/ed25519.h"
+#include "hasher.h"
+#include "hmac_drbg.h"
+#include "memzero.h"
+#include "monero/monero.h"
+#include "nem.h"
+#include "nist256p1.h"
+#include "pbkdf2.h"
+#include "rand.h"
+#include "rc4.h"
+#include "rfc6979.h"
+#include "script.h"
+#include "secp256k1.h"
+#include "segwit_addr.h"
+#include "sha2.h"
+#include "sha3.h"
+#include "shamir.h"
+#include "slip39.h"
+#include "slip39_wordlist.h"
+#include "zkp_bip340.h"
+#include "zkp_context.h"
+#include "zkp_ecdsa.h"
+
+#if defined(__has_feature)
+#if __has_feature(memory_sanitizer)
+#include <sanitizer/msan_interface.h>
+#endif
+#endif
+
+/* code design notes
+ *
+ * TODO note down design tradeoffs for this fuzzer style
+ */
+
+/* code performance notes
+ *
+ * use #define over runtime checks for performance reasons
+ * avoid VLA arrays for performance reasons
+ * potential performance drawbacks of heap usage are accepted for better out of
+ * bounds error detection some expensive functions are hidden with compile-time
+ * switches fuzzer harnesses are meant to exit early if the preconditions are
+ * not met
+ */
+
+/* fuzzer input data handling */
+const uint8_t *fuzzer_ptr;
+size_t fuzzer_length;
+
+const uint8_t *fuzzer_input(size_t len) {
+  if (fuzzer_length < len) {
+    fuzzer_length = 0;
+    return NULL;
+  }
+  const uint8_t *result = fuzzer_ptr;
+  fuzzer_length -= len;
+  fuzzer_ptr += len;
+  return result;
+}
+
+/* fuzzer state handling */
+void fuzzer_reset_state(void) {
+  // reset the PRNGs to make individual fuzzer runs deterministic
+  srand(0);
+  random_reseed(0);
+
+  // clear internal caches
+  // note: this is not strictly required for all fuzzer targets
+#if USE_BIP32_CACHE
+  bip32_cache_clear();
+#endif
+#if USE_BIP39_CACHE
+  bip39_cache_clear();
+#endif
+}
+
+void crash(void) {
+  // intentionally exit the program
+  // the fuzzer framework treats this as a crash
+  exit(1);
+}
+
+// IDEA are there advantages to turning this into a macro?
+//
+// check the memory area for memory information leaks if MSAN is available,
+// crash if problems are detected
+void check_msan(void *pointer, size_t length) {
+#if defined(__has_feature)
+#if __has_feature(memory_sanitizer)
+  // check `address` for memory info leakage
+  __msan_check_mem_is_initialized(pointer, length);
+#else
+  // ignore if MSan is not enabled
+  (void)pointer;
+  (void)length;
+#endif
+#else
+  // ignore if the compiler does not know __has_feature()
+  (void)pointer;
+  (void)length;
+#endif
+}
+
+// simplify the pointer check after a var_pointer = malloc()
+// return -1 to mark fuzz input as uninteresting for the fuzz engine
+// warning: use only if no manual memory cleanup is needed
+#define RETURN_IF_NULL(var_pointer) \
+  if (var_pointer == NULL) {        \
+    return -1;                      \
+  }
+
+void zkp_initialize_context_or_crash(void) {
+  // The current context usage has persistent side effects
+  // TODO switch to frequent re-initialization where necessary
+  if (!zkp_context_is_initialized()) {
+    if (zkp_context_init() != 0) {
+      crash();
+    }
+  }
+}
+
+/* individual fuzzer harness functions */
+
+int fuzz_bn_format(void) {
+  bignum256 target_bignum;
+  // we need some amount of initial data
+  if (fuzzer_length < sizeof(target_bignum) + 1 + 1) {
+    return -1;
+  }
+
+#define FUZZ_BN_FORMAT_OUTPUT_BUFFER_SIZE 512
+  char buf[FUZZ_BN_FORMAT_OUTPUT_BUFFER_SIZE] = {0};
+  int ret = 0;
+
+  // mutate the struct contents
+  memcpy(&target_bignum, fuzzer_input(sizeof(target_bignum)),
+         sizeof(target_bignum));
+
+  uint8_t prefixlen = 0;
+  uint8_t suffixlen = 0;
+  uint32_t decimals = 0;
+  int32_t exponent = 0;
+  bool trailing = false;
+  // range 1 to 128
+  prefixlen = (fuzzer_input(1)[0] & 127) + 1;
+  suffixlen = (fuzzer_input(1)[0] & 127) + 1;
+
+  // check for the second half of the data
+  if (fuzzer_length < (size_t)(prefixlen + suffixlen + 4 + 4 + 1 - 2)) {
+    return -1;
+  }
+  memcpy(&decimals, fuzzer_input(4), 4);
+  memcpy(&exponent, fuzzer_input(4), 4);
+  trailing = (fuzzer_input(1)[0] & 1);
+
+  // IDEA allow prefix == NULL
+  char *prefix = malloc(prefixlen);
+  RETURN_IF_NULL(prefix);
+  // IDEA allow suffix == NULL
+  char *suffix = malloc(suffixlen);
+  if (suffix == NULL) {
+    free(prefix);
+    return -1;
+  }
+
+  memset(prefix, 0, prefixlen);
+  memset(suffix, 0, suffixlen);
+  // only fetch up to (length - 1) to ensure null termination together with the
+  // memset
+  memcpy(prefix, fuzzer_input(prefixlen - 1), prefixlen - 1);
+  memcpy(suffix, fuzzer_input(suffixlen - 1), suffixlen - 1);
+
+  ret = bn_format(&target_bignum, prefix, suffix, decimals, exponent, trailing,
+                  0, buf, FUZZ_BN_FORMAT_OUTPUT_BUFFER_SIZE);
+
+  // basic sanity checks for the return values
+  if (ret > FUZZ_BN_FORMAT_OUTPUT_BUFFER_SIZE) {
+    crash();
+  }
+
+  check_msan(&buf, FUZZ_BN_FORMAT_OUTPUT_BUFFER_SIZE);
+
+  free(prefix);
+  free(suffix);
+  return 0;
+}
+
+// arbitrarily chosen maximum size
+#define BASE32_DECODE_MAX_INPUT_LEN 512
+
+int fuzz_base32_decode(void) {
+  if (fuzzer_length < 2 || fuzzer_length > BASE32_DECODE_MAX_INPUT_LEN) {
+    return -1;
+  }
+
+  char *in_buffer = malloc(fuzzer_length);
+  RETURN_IF_NULL(in_buffer);
+  // basic heuristic: the decoded output will always fit in less or equal space
+  uint8_t *out_buffer = malloc(fuzzer_length);
+  if (out_buffer == NULL) {
+    free(in_buffer);
+    return -1;
+  }
+
+  size_t outlen = fuzzer_length;
+  size_t raw_inlen = fuzzer_length;
+  memcpy(in_buffer, fuzzer_input(raw_inlen), raw_inlen);
+
+  // null-terminate input buffer to prevent issues with strlen()
+  in_buffer[raw_inlen - 1] = 0;
+
+  uint8_t *ret = base32_decode(in_buffer, raw_inlen, out_buffer, outlen,
+                               BASE32_ALPHABET_RFC4648);
+
+  if (ret != NULL) {
+    check_msan(out_buffer, outlen);
+  }
+  free(in_buffer);
+  free(out_buffer);
+  return 0;
+}
+
+// arbitrarily chosen maximum size
+#define BASE32_ENCODE_MAX_INPUT_LEN 512
+
+int fuzz_base32_encode(void) {
+  if (fuzzer_length > BASE32_ENCODE_MAX_INPUT_LEN) {
+    return -1;
+  }
+
+  uint8_t *in_buffer = malloc(fuzzer_length);
+  RETURN_IF_NULL(in_buffer);
+  // TODO: find a better heuristic for output buffer size
+  size_t outlen = 2 * fuzzer_length;
+  char *out_buffer = malloc(outlen);
+  if (out_buffer == NULL) {
+    free(in_buffer);
+    return -1;
+  }
+
+  // mutate in_buffer
+  size_t raw_inlen = fuzzer_length;
+  memcpy(in_buffer, fuzzer_ptr, raw_inlen);
+  fuzzer_input(raw_inlen);
+
+  char *ret = base32_encode(in_buffer, raw_inlen, out_buffer, outlen,
+                            BASE32_ALPHABET_RFC4648);
+
+  if (ret != NULL) {
+    // the return value is a pointer to the end of the written buffer,
+    // use it to calculate the used buffer area
+    check_msan(out_buffer, ret - out_buffer);
+  }
+  free(in_buffer);
+  free(out_buffer);
+  return 0;
+}
+
+// internal limit is 128, try some extra bytes
+#define BASE58_ENCODE_MAX_INPUT_LEN 140
+
+int fuzz_base58_encode_check(void) {
+  if (fuzzer_length > BASE58_ENCODE_MAX_INPUT_LEN) {
+    return -1;
+  }
+
+  uint8_t *in_buffer = malloc(fuzzer_length);
+  RETURN_IF_NULL(in_buffer);
+  // TODO: find a better heuristic for output buffer size
+  size_t outlen = 2 * fuzzer_length;
+  char *out_buffer = malloc(outlen);
+  if (out_buffer == NULL) {
+    free(in_buffer);
+    return -1;
+  }
+
+  // mutate in_buffer
+  size_t raw_inlen = fuzzer_length;
+  memcpy(in_buffer, fuzzer_input(raw_inlen), raw_inlen);
+
+  int ret = 0;
+  // run multiple hasher variants for the same input
+  base58_encode_check(in_buffer, raw_inlen, HASHER_SHA2D, out_buffer, outlen);
+  base58_encode_check(in_buffer, raw_inlen, HASHER_BLAKED, out_buffer, outlen);
+  base58_encode_check(in_buffer, raw_inlen, HASHER_GROESTLD_TRUNC, out_buffer,
+                      outlen);
+  ret = base58_encode_check(in_buffer, raw_inlen, HASHER_SHA3K, out_buffer,
+                            outlen);
+
+  // check one of the encode results
+  if (ret != 0) {
+    // the return value describes how many characters are written
+    check_msan(out_buffer, ret);
+  }
+
+  free(in_buffer);
+  free(out_buffer);
+  return 0;
+}
+
+// internal limit is 128, try some extra bytes
+#define BASE58_DECODE_MAX_INPUT_LEN 140
+
+int fuzz_base58_decode_check(void) {
+  if (fuzzer_length > BASE58_DECODE_MAX_INPUT_LEN) {
+    return -1;
+  }
+
+  uint8_t *in_buffer = malloc(fuzzer_length + 1);
+  RETURN_IF_NULL(in_buffer);
+
+  size_t raw_inlen = fuzzer_length;
+  memcpy(in_buffer, fuzzer_input(raw_inlen), raw_inlen);
+  uint8_t out_buffer[MAX_ADDR_RAW_SIZE] = {0};
+  // force null-termination
+  in_buffer[raw_inlen] = 0;
+  const char *in_char = (const char *)in_buffer;
+
+  // run multiple hasher variants for the same input
+  base58_decode_check(in_char, HASHER_SHA2D, out_buffer, MAX_ADDR_RAW_SIZE);
+  base58_decode_check(in_char, HASHER_BLAKED, out_buffer, MAX_ADDR_RAW_SIZE);
+  base58_decode_check(in_char, HASHER_GROESTLD_TRUNC, out_buffer,
+                      MAX_ADDR_RAW_SIZE);
+  base58_decode_check(in_char, HASHER_SHA3K, out_buffer, MAX_ADDR_RAW_SIZE);
+
+  check_msan(out_buffer, MAX_ADDR_RAW_SIZE);
+
+  free(in_buffer);
+  return 0;
+}
+
+// arbitrarily chosen maximum size meant to limit input complexity
+// there is no input size limit for the target function
+#define XMR_BASE58_ADDR_DECODE_MAX_INPUT_LEN 512
+
+int fuzz_xmr_base58_addr_decode_check(void) {
+  if (fuzzer_length > XMR_BASE58_ADDR_DECODE_MAX_INPUT_LEN) {
+    return -1;
+  }
+
+  // TODO no null termination used !?
+  // TODO use better size heuristic
+  size_t outlen = fuzzer_length;
+  char *in_buffer = malloc(fuzzer_length);
+  RETURN_IF_NULL(in_buffer);
+  uint8_t *out_buffer = malloc(outlen);
+  if (out_buffer == NULL) {
+    free(in_buffer);
+    return -1;
+  }
+
+  // tag is only written to
+  uint64_t tag = 0;
+  size_t raw_inlen = fuzzer_length;
+  // mutate in_buffer
+  memcpy(in_buffer, fuzzer_input(raw_inlen), raw_inlen);
+
+  int ret = xmr_base58_addr_decode_check(in_buffer, raw_inlen, &tag, out_buffer,
+                                         outlen);
+
+  // IDEA check tag for expected values?
+  // IDEA re-encode valid decoding results to check function consistency?
+
+  if (ret != 0) {
+    check_msan(out_buffer, outlen);
+  }
+
+  free(in_buffer);
+  free(out_buffer);
+  return 0;
+}
+
+// arbitrarily chosen maximum size
+#define XMR_BASE58_DECODE_MAX_INPUT_LEN 512
+// a more focused variant of the xmr_base58_addr_decode_check() harness
+int fuzz_xmr_base58_decode(void) {
+  if (fuzzer_length > XMR_BASE58_DECODE_MAX_INPUT_LEN) {
+    return -1;
+  }
+
+  // TODO better size heuristic
+  size_t outlen = fuzzer_length;
+  char *in_buffer = malloc(fuzzer_length);
+  RETURN_IF_NULL(in_buffer);
+  uint8_t *out_buffer = malloc(outlen);
+  if (out_buffer == NULL) {
+    free(in_buffer);
+    return -1;
+  }
+
+  memset(out_buffer, 0, outlen);
+
+  // mutate in_buffer
+  size_t raw_inlen = fuzzer_length;
+  memcpy(in_buffer, fuzzer_input(raw_inlen), raw_inlen);
+
+  xmr_base58_decode(in_buffer, raw_inlen, out_buffer, &outlen);
+
+  free(in_buffer);
+  free(out_buffer);
+  return 0;
+}
+
+// arbitrarily chosen maximum size
+#define XMR_BASE58_ADDR_ENCODE_MAX_INPUT_LEN 140
+
+int fuzz_xmr_base58_addr_encode_check(void) {
+  // tag_in is internally limited
+  uint8_t tag_in;
+  int ret1 = 0;
+  size_t tag_size = sizeof(tag_in);
+  if (fuzzer_length < tag_size + 1 ||
+      fuzzer_length > XMR_BASE58_ADDR_ENCODE_MAX_INPUT_LEN) {
+    return -1;
+  }
+
+  // mutate tag_in
+  memcpy(&tag_in, fuzzer_input(tag_size), tag_size);
+
+  // TODO better size heuristic
+  size_t outlen = fuzzer_length * 2;
+  uint8_t *in_buffer = malloc(fuzzer_length);
+  RETURN_IF_NULL(in_buffer);
+  char *out_buffer = malloc(outlen);
+  if (out_buffer == NULL) {
+    free(in_buffer);
+    return -1;
+  }
+
+  memset(out_buffer, 0, outlen);
+
+  // mutate in_buffer
+  size_t raw_inlen = fuzzer_length;
+  memcpy(in_buffer, fuzzer_input(raw_inlen), raw_inlen);
+
+  ret1 = xmr_base58_addr_encode_check(tag_in, in_buffer, raw_inlen, out_buffer,
+                                      outlen);
+
+  if (ret1 != 0) {
+    // encoding successful
+    uint64_t second_tag = 0;
+    // TODO improve length
+    uint8_t dummy_buffer[XMR_BASE58_ADDR_ENCODE_MAX_INPUT_LEN] = {0};
+    int ret2 = 0;
+    // ret1 represents the actual length of the encoded string
+    // this is important for the decode function to succeed
+    ret2 = xmr_base58_addr_decode_check(out_buffer, ret1, &second_tag,
+                                        dummy_buffer, sizeof(dummy_buffer));
+    // the tag comparison is between unequal types, but this is acceptable here
+    if (ret2 == 0 || tag_in != second_tag) {
+      crash();
+    }
+  }
+
+  free(in_buffer);
+  free(out_buffer);
+  return 0;
+}
+
+// arbitrarily chosen maximum size
+#define XMR_BASE58_ENCODE_MAX_INPUT_LEN 512
+// a more focused variant of the xmr_base58_addr_encode_check() harness
+int fuzz_xmr_base58_encode(void) {
+  if (fuzzer_length > XMR_BASE58_ENCODE_MAX_INPUT_LEN) {
+    return -1;
+  }
+
+  // TODO better size heuristic
+  size_t outlen = fuzzer_length * 2;
+  uint8_t *in_buffer = malloc(fuzzer_length);
+  RETURN_IF_NULL(in_buffer);
+  char *out_buffer = malloc(outlen);
+  if (out_buffer == NULL) {
+    free(in_buffer);
+    return -1;
+  }
+
+  memset(out_buffer, 0, outlen);
+
+  // mutate in_buffer
+  size_t raw_inlen = fuzzer_length;
+  memcpy(in_buffer, fuzzer_input(raw_inlen), raw_inlen);
+
+  xmr_base58_encode(out_buffer, &outlen, in_buffer, raw_inlen);
+
+  free(in_buffer);
+  free(out_buffer);
+  return 0;
+}
+
+int fuzz_xmr_serialize_varint(void) {
+// arbitrarily chosen maximum size
+#define XMR_SERIALIZE_VARINT_MAX_INPUT_LEN 128
+
+  uint64_t varint_in;
+  size_t varint_in_size = sizeof(varint_in);
+  if (fuzzer_length <= varint_in_size ||
+      fuzzer_length > XMR_SERIALIZE_VARINT_MAX_INPUT_LEN) {
+    return -1;
+  }
+
+  uint8_t out_buffer[XMR_SERIALIZE_VARINT_MAX_INPUT_LEN] = {0};
+  size_t outlen = sizeof(out_buffer);
+  uint64_t varint_out = 0;
+
+  // mutate varint_in
+  memcpy(&varint_in, fuzzer_input(varint_in_size), varint_in_size);
+
+  // mutate in_buffer
+  size_t raw_inlen = fuzzer_length;
+  uint8_t *in_buffer = malloc(raw_inlen);
+  RETURN_IF_NULL(in_buffer);
+  memcpy(in_buffer, fuzzer_input(raw_inlen), raw_inlen);
+
+  // use the varint
+  xmr_size_varint(varint_in);
+  xmr_write_varint(out_buffer, outlen, varint_in);
+
+  // use the input buffer
+  xmr_read_varint(in_buffer, raw_inlen, &varint_out);
+
+  // IDEA cross-check write/read results
+
+  free(in_buffer);
+  return 0;
+}
+
+// arbitrarily chosen maximum size
+#define NEM_VALIDATE_ADDRESS_MAX_INPUT_LEN 128
+
+int fuzz_nem_validate_address(void) {
+  if (fuzzer_length < 1 || fuzzer_length > NEM_VALIDATE_ADDRESS_MAX_INPUT_LEN) {
+    return -1;
+  }
+
+  uint8_t network = fuzzer_input(1)[0];
+  size_t raw_inlen = fuzzer_length + 1;
+  char *in_buffer = malloc(raw_inlen);
+  RETURN_IF_NULL(in_buffer);
+
+  // mutate the buffer
+  memcpy(in_buffer, fuzzer_input(raw_inlen - 1), raw_inlen - 1);
+  // force null-termination
+  in_buffer[raw_inlen - 1] = 0;
+
+  nem_validate_address(in_buffer, network);
+
+  free(in_buffer);
+  return 0;
+}
+
+int fuzz_nem_get_address(void) {
+  unsigned char ed25519_public_key_fuzz[32] = {0};
+  uint8_t version = 0;
+
+  // TODO switch to < comparison?
+  if (fuzzer_length != (sizeof(ed25519_public_key_fuzz) + sizeof(version))) {
+    return -1;
+  }
+
+  char address[NEM_ADDRESS_SIZE + 1] = {0};
+
+  memcpy(ed25519_public_key_fuzz, fuzzer_input(sizeof(ed25519_public_key_fuzz)),
+         sizeof(ed25519_public_key_fuzz));
+  memcpy(&version, fuzzer_input(sizeof(version)), sizeof(version));
+
+  nem_get_address(ed25519_public_key_fuzz, version, address);
+
+  check_msan(&address, sizeof(address));
+  return 0;
+}
+
+int fuzz_xmr_get_subaddress_secret_key(void) {
+  bignum256modm m = {0};
+  uint32_t major = 0;
+  uint32_t minor = 0;
+  if (fuzzer_length != (sizeof(bignum256modm) + 2 * sizeof(uint32_t))) {
+    return -1;
+  }
+
+  bignum256modm output = {0};
+
+  memcpy(m, fuzzer_input(sizeof(bignum256modm)), sizeof(bignum256modm));
+  memcpy(&major, fuzzer_input(sizeof(uint32_t)), sizeof(uint32_t));
+  memcpy(&minor, fuzzer_input(sizeof(uint32_t)), sizeof(uint32_t));
+
+  xmr_get_subaddress_secret_key(output, major, minor, m);
+
+  check_msan(&output, sizeof(output));
+  return 0;
+}
+
+int fuzz_xmr_derive_private_key(void) {
+  bignum256modm base = {0};
+  ge25519 deriv = {0};
+  uint32_t idx = 0;
+
+  if (fuzzer_length !=
+      (sizeof(bignum256modm) + sizeof(ge25519) + sizeof(uint32_t))) {
+    return -1;
+  }
+
+  memcpy(base, fuzzer_input(sizeof(bignum256modm)), sizeof(bignum256modm));
+  memcpy(&deriv, fuzzer_input(sizeof(ge25519)), sizeof(ge25519));
+  memcpy(&idx, fuzzer_input(sizeof(uint32_t)), sizeof(uint32_t));
+
+  bignum256modm output = {0};
+
+  xmr_derive_private_key(output, &deriv, idx, base);
+  check_msan(&output, sizeof(output));
+  return 0;
+}
+
+int fuzz_xmr_derive_public_key(void) {
+  ge25519 base = {0};
+  ge25519 deriv = {0};
+  uint32_t idx = 0;
+
+  if (fuzzer_length != (2 * sizeof(ge25519) + sizeof(uint32_t))) {
+    return -1;
+  }
+
+  memcpy(&base, fuzzer_input(sizeof(ge25519)), sizeof(ge25519));
+  memcpy(&deriv, fuzzer_input(sizeof(ge25519)), sizeof(ge25519));
+  memcpy(&idx, fuzzer_input(sizeof(uint32_t)), sizeof(uint32_t));
+
+  ge25519 output = {0};
+
+  xmr_derive_public_key(&output, &deriv, idx, &base);
+  check_msan(&output, sizeof(output));
+  return 0;
+}
+
+#define SHAMIR_MAX_SHARE_COUNT 16
+#define SHAMIR_MAX_DATA_LEN (SHAMIR_MAX_SHARE_COUNT * SHAMIR_MAX_LEN)
+int fuzz_shamir_interpolate(void) {
+  if (fuzzer_length != (2 * sizeof(uint8_t) + SHAMIR_MAX_SHARE_COUNT +
+                        SHAMIR_MAX_DATA_LEN + sizeof(size_t))) {
+    return -1;
+  }
+
+  uint8_t result[SHAMIR_MAX_LEN] = {0};
+  uint8_t result_index = 0;
+  uint8_t share_indices[SHAMIR_MAX_SHARE_COUNT] = {0};
+  uint8_t share_values_content[SHAMIR_MAX_SHARE_COUNT][SHAMIR_MAX_LEN] = {0};
+  const uint8_t *share_values[SHAMIR_MAX_SHARE_COUNT] = {0};
+  uint8_t share_count = 0;
+  size_t len = 0;
+
+  for (size_t i = 0; i < SHAMIR_MAX_SHARE_COUNT; i++) {
+    share_values[i] = share_values_content[i];
+  }
+
+  memcpy(&result_index, fuzzer_input(sizeof(uint8_t)), sizeof(uint8_t));
+  memcpy(&share_indices, fuzzer_input(SHAMIR_MAX_SHARE_COUNT),
+         SHAMIR_MAX_SHARE_COUNT);
+  memcpy(&share_values_content, fuzzer_input(SHAMIR_MAX_DATA_LEN),
+         SHAMIR_MAX_DATA_LEN);
+  memcpy(&share_count, fuzzer_input(sizeof(uint8_t)), sizeof(uint8_t));
+  // note: this is platform specific via byte length of size_t
+  memcpy(&len, fuzzer_input(sizeof(size_t)), sizeof(size_t));
+
+  // mirror a check that the real code does
+  if (share_count < 1 || share_count > SHAMIR_MAX_SHARE_COUNT) {
+    return 0;
+  }
+  // (len > SHAMIR_MAX_LEN) is handled in the target function
+
+  shamir_interpolate(result, result_index, share_indices, share_values,
+                     share_count, len);
+  check_msan(&result, sizeof(result));
+  return 0;
+}
+
+int fuzz_ecdsa_sign_digest_functions(void) {
+  // bug result reference: https://github.com/trezor/trezor-firmware/pull/1697
+
+  uint8_t curve_decider = 0;
+  uint8_t priv_key[32] = {0};
+  uint8_t digest[32] = {0};
+
+  uint8_t sig1[64] = {0};
+  uint8_t sig2[64] = {0};
+  uint8_t pby1, pby2 = 0;
+  if (fuzzer_length < 1 + sizeof(priv_key) + sizeof(digest)) {
+    return -1;
+  }
+  const ecdsa_curve *curve;
+
+  memcpy(&curve_decider, fuzzer_input(1), 1);
+  memcpy(&priv_key, fuzzer_input(sizeof(priv_key)), sizeof(priv_key));
+  memcpy(&digest, fuzzer_input(sizeof(digest)), sizeof(digest));
+
+  // pick one of the standard curves
+  if ((curve_decider & 0x1) == 1) {
+    curve = &secp256k1;
+  } else {
+    curve = &nist256p1;
+  }
+
+  int res = 0;
+
+  // IDEA optionally set a function for is_canonical() callback
+  int res1 = ecdsa_sign_digest(curve, priv_key, digest, sig1, &pby1, NULL);
+
+  // the zkp function variant is only defined for a specific curve
+  if (curve == &secp256k1) {
+    int res2 =
+        zkp_ecdsa_sign_digest(curve, priv_key, digest, sig2, &pby2, NULL);
+    if ((res1 == 0 && res2 != 0) || (res1 != 0 && res2 == 0)) {
+      // one variant succeeded where the other did not
+      crash();
+    }
+    if (res1 == 0 && res2 == 0) {
+      if ((pby1 != pby2) || memcmp(&sig1, &sig2, sizeof(sig1)) != 0) {
+        // result values are different
+        crash();
+      }
+    }
+  }
+
+  // successful signing
+  if (res1 == 0) {
+    uint8_t pub_key[33] = {0};
+    res = ecdsa_get_public_key33(curve, priv_key, pub_key);
+    if (res != 0) {
+      // pubkey derivation did not succeed
+      crash();
+    }
+
+    res = ecdsa_verify_digest(curve, pub_key, sig1, digest);
+    if (res != 0) {
+      // verification did not succeed
+      crash();
+    }
+  }
+  return 0;
+}
+
+int fuzz_ecdsa_verify_digest_functions(void) {
+  uint8_t curve_decider = 0;
+  uint8_t hash[32] = {0};
+  uint8_t sig[64] = {0};
+  uint8_t pub_key[65] = {0};
+
+  if (fuzzer_length < 1 + sizeof(hash) + sizeof(sig) + sizeof(pub_key)) {
+    return -1;
+  }
+
+  memcpy(&curve_decider, fuzzer_input(1), 1);
+  memcpy(&hash, fuzzer_input(sizeof(hash)), sizeof(hash));
+  memcpy(&sig, fuzzer_input(sizeof(sig)), sizeof(sig));
+  memcpy(&pub_key, fuzzer_input(sizeof(pub_key)), sizeof(pub_key));
+
+  const ecdsa_curve *curve;
+  // pick one of the standard curves
+  if ((curve_decider & 0x1) == 1) {
+    curve = &secp256k1;
+  } else {
+    curve = &nist256p1;
+  }
+
+  int res1 = ecdsa_verify_digest(curve, (const uint8_t *)&pub_key,
+                                 (const uint8_t *)&sig, (const uint8_t *)&hash);
+  if (res1 == 0) {
+    // See if the fuzzer ever manages to get find a correct verification
+    // intentionally trigger a crash to make this case observable
+    // TODO this is not an actual problem, remove in the future
+    crash();
+  }
+
+  // the zkp_ecdsa* function only accepts the secp256k1 curve
+  if (curve == &secp256k1) {
+    int res2 =
+        zkp_ecdsa_verify_digest(curve, (const uint8_t *)&pub_key,
+                                (const uint8_t *)&sig, (const uint8_t *)&hash);
+
+    // the error code behavior is different between both functions, compare only
+    // verification state
+    if ((res1 == 0 && res2 != 0) || (res1 != 0 && res2 == 0)) {
+      // results differ, this is a problem
+      crash();
+    }
+  }
+
+  return 0;
+}
+
+int fuzz_word_index(void) {
+#define MAX_WORD_LENGTH 12
+
+  if (fuzzer_length < MAX_WORD_LENGTH) {
+    return -1;
+  }
+
+  char word[MAX_WORD_LENGTH + 1] = {0};
+  memcpy(&word, fuzzer_ptr, MAX_WORD_LENGTH);
+  size_t word_length = strlen(word);
+  uint16_t index = 0;
+
+  word_index(&index, (const char *)&word, word_length);
+
+  return 0;
+}
+
+int fuzz_slip39_word_completion_mask(void) {
+  if (fuzzer_length != 2) {
+    return -1;
+  }
+  uint16_t sequence = (fuzzer_ptr[0] << 8) + fuzzer_ptr[1];
+  fuzzer_input(2);
+
+  slip39_word_completion_mask(sequence);
+
+  return 0;
+}
+
+// regular MAX_MNEMONIC_LEN is 240, try some extra bytes
+#define MAX_MNEMONIC_FUZZ_LENGTH 256
+int fuzz_mnemonic_check(void) {
+  if (fuzzer_length < MAX_MNEMONIC_FUZZ_LENGTH) {
+    return -1;
+  }
+
+  char mnemonic[MAX_MNEMONIC_FUZZ_LENGTH + 1] = {0};
+  memcpy(&mnemonic, fuzzer_ptr, MAX_MNEMONIC_FUZZ_LENGTH);
+
+  // at the time of creation of this fuzzer harness, mnemonic_check()
+  // internally calls mnemonic_to_bits() while checking the result
+  int ret = mnemonic_check(mnemonic);
+
+  (void)ret;
+  /*
+  if(ret == 1) {
+    // correct result
+  }
+  */
+
+  return 0;
+}
+
+int fuzz_mnemonic_from_data(void) {
+  if (fuzzer_length < 16 || fuzzer_length > 32) {
+    return -1;
+  }
+
+  const char *mnemo_result = mnemonic_from_data(fuzzer_ptr, fuzzer_length);
+  if (mnemo_result != NULL) {
+    int res = mnemonic_check(mnemo_result);
+    if (res == 0) {
+      // TODO the mnemonic_check() function is currently incorrectly rejecting
+      // valid 15 and 21 word seeds
+      // remove this workaround limitation later
+      if (fuzzer_length != 20 && fuzzer_length != 28) {
+        // the generated mnemonic has an invalid format
+        crash();
+      }
+    }
+  }
+  // scrub the internal buffer to rule out persistent side effects
+  mnemonic_clear();
+  return 0;
+}
+
+// passphrase normally has a 64 or 256 byte length maximum
+#define MAX_PASSPHRASE_FUZZ_LENGTH 257
+int fuzz_mnemonic_to_seed(void) {
+  if (fuzzer_length < MAX_MNEMONIC_FUZZ_LENGTH + MAX_PASSPHRASE_FUZZ_LENGTH) {
+    return -1;
+  }
+
+  char mnemonic[MAX_PASSPHRASE_FUZZ_LENGTH + 1] = {0};
+  char passphrase[MAX_MNEMONIC_FUZZ_LENGTH + 1] = {0};
+  uint8_t seed[512 / 8] = {0};
+
+  memcpy(&mnemonic, fuzzer_input(MAX_MNEMONIC_FUZZ_LENGTH),
+         MAX_MNEMONIC_FUZZ_LENGTH);
+  memcpy(&passphrase, fuzzer_input(MAX_PASSPHRASE_FUZZ_LENGTH),
+         MAX_PASSPHRASE_FUZZ_LENGTH);
+
+  mnemonic_to_seed(mnemonic, passphrase, seed, NULL);
+
+  return 0;
+}
+
+int fuzz_ethereum_address_checksum(void) {
+  uint8_t addr[20] = {0};
+  char address[43] = {0};
+  uint64_t chain_id = 0;
+  bool rskip60 = false;
+
+  if (fuzzer_length < sizeof(addr) + sizeof(address) + sizeof(chain_id) + 1) {
+    return -1;
+  }
+
+  memcpy(addr, fuzzer_input(sizeof(addr)), sizeof(addr));
+  memcpy(address, fuzzer_input(sizeof(address)), sizeof(address));
+  memcpy(&chain_id, fuzzer_input(sizeof(chain_id)), sizeof(chain_id));
+  // usually dependent on chain_id, but determined separately here
+  rskip60 = (*fuzzer_input(1)) & 0x1;
+
+  ethereum_address_checksum(addr, address, rskip60, chain_id);
+
+  return 0;
+}
+
+int fuzz_aes(void) {
+  if (fuzzer_length < 1 + 16 + 16 + 32) {
+    return -1;
+  }
+
+  aes_encrypt_ctx ctxe;
+  aes_decrypt_ctx ctxd;
+  uint8_t ibuf[16] = {0};
+  uint8_t obuf[16] = {0};
+  uint8_t iv[16] = {0};
+  uint8_t cbuf[16] = {0};
+
+  const uint8_t *keylength_decider = fuzzer_input(1);
+
+  // note: the unit test uses the fixed 32 byte key
+  // 603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4
+  uint8_t keybuf[32] = {0};
+  memcpy(&keybuf, fuzzer_input(32), 32);
+
+#ifdef AES_VAR
+  // try 128, 192, 256 bit key lengths
+
+  size_t keylength = 32;
+  switch (keylength_decider[0] & 0x3) {
+    case 0:
+      // invalid length
+      keylength = 1;
+      break;
+    case 1:
+      keylength = 16;
+      break;
+    case 2:
+      keylength = 24;
+      break;
+    case 3:
+      keylength = 32;
+      break;
+  }
+
+  if (aes_encrypt_key((const unsigned char *)&keybuf, keylength, &ctxe) ||
+      aes_decrypt_key((const unsigned char *)&keybuf, keylength, &ctxd)) {
+    // initialization problems, stop processing
+    // we expect this to happen with the invalid key length
+    return 0;
+  }
+#else
+  // use a 256 bit key length
+  (void)keylength_decider;
+  aes_encrypt_key256((const unsigned char *)&keybuf, &ctxe);
+  aes_decrypt_key256((const unsigned char *)&keybuf, &ctxd);
+#endif
+
+  memcpy(ibuf, fuzzer_input(16), 16);
+  memcpy(iv, fuzzer_input(16), 16);
+
+  aes_ecb_encrypt(ibuf, obuf, 16, &ctxe);
+  aes_ecb_decrypt(ibuf, obuf, 16, &ctxd);
+
+  aes_cbc_encrypt(ibuf, obuf, 16, iv, &ctxe);
+  aes_cbc_decrypt(ibuf, obuf, 16, iv, &ctxd);
+
+  aes_cfb_encrypt(ibuf, obuf, 16, iv, &ctxe);
+  aes_cfb_decrypt(ibuf, obuf, 16, iv, &ctxe);
+
+  aes_ofb_encrypt(ibuf, obuf, 16, iv, &ctxe);
+  aes_ofb_decrypt(ibuf, obuf, 16, iv, &ctxe);
+
+  aes_ctr_encrypt(ibuf, obuf, 16, cbuf, aes_ctr_cbuf_inc, &ctxe);
+  aes_ctr_decrypt(ibuf, obuf, 16, cbuf, aes_ctr_cbuf_inc, &ctxe);
+  return 0;
+}
+
+int fuzz_chacha_drbg(void) {
+#define CHACHA_DRBG_ENTROPY_LENGTH 32
+#define CHACHA_DRBG_RESEED_LENGTH 32
+#define CHACHA_DRBG_NONCE_LENGTH 16
+#define CHACHA_DRBG_RESULT_LENGTH 16
+
+  if (fuzzer_length < CHACHA_DRBG_ENTROPY_LENGTH + CHACHA_DRBG_RESEED_LENGTH +
+                          CHACHA_DRBG_NONCE_LENGTH) {
+    return -1;
+  }
+
+  uint8_t entropy[CHACHA_DRBG_ENTROPY_LENGTH] = {0};
+  uint8_t reseed[CHACHA_DRBG_RESEED_LENGTH] = {0};
+  uint8_t nonce_bytes[CHACHA_DRBG_NONCE_LENGTH] = {0};
+  uint8_t result[CHACHA_DRBG_RESULT_LENGTH] = {0};
+  CHACHA_DRBG_CTX ctx;
+
+  // IDEA switch to variable input sizes
+  memcpy(&entropy, fuzzer_input(CHACHA_DRBG_ENTROPY_LENGTH),
+         CHACHA_DRBG_ENTROPY_LENGTH);
+  memcpy(&reseed, fuzzer_input(CHACHA_DRBG_RESEED_LENGTH),
+         CHACHA_DRBG_RESEED_LENGTH);
+  memcpy(&nonce_bytes, fuzzer_input(CHACHA_DRBG_NONCE_LENGTH),
+         CHACHA_DRBG_NONCE_LENGTH);
+
+  chacha_drbg_init(&ctx, entropy, sizeof(entropy), nonce_bytes,
+                   sizeof(nonce_bytes));
+  chacha_drbg_reseed(&ctx, reseed, sizeof(reseed), NULL, 0);
+  chacha_drbg_generate(&ctx, result, sizeof(result));
+
+  return 0;
+}
+
+int fuzz_ed25519_sign_verify(void) {
+  ed25519_secret_key secret_key;
+  ed25519_signature signature;
+  ed25519_public_key public_key;
+  // length chosen arbitrarily
+  uint8_t message[32] = {0};
+  int ret = 0;
+
+  if (fuzzer_length <
+      sizeof(secret_key) + sizeof(signature) + sizeof(message)) {
+    return -1;
+  }
+
+  memcpy(&secret_key, fuzzer_input(sizeof(secret_key)), sizeof(secret_key));
+  memcpy(&signature, fuzzer_input(sizeof(signature)), sizeof(signature));
+  memcpy(&message, fuzzer_input(sizeof(message)), sizeof(message));
+
+  ed25519_publickey(secret_key, public_key);
+  // sign message, this should always succeed
+  ed25519_sign(message, sizeof(message), secret_key, signature);
+
+  // verify message, we expect this to work
+  ret = ed25519_sign_open(message, sizeof(message), public_key, signature);
+
+  if (ret != 0) {
+    // verification did not succeed
+    crash();
+  }
+
+  return 0;
+}
+
+int fuzz_zkp_bip340_sign_digest(void) {
+  uint8_t priv_key[32] = {0};
+  uint8_t aux_input[32] = {0};
+  uint8_t digest[32] = {0};
+  uint8_t pub_key[32] = {0};
+  uint8_t sig[64] = {0};
+
+  if (fuzzer_length <
+      sizeof(priv_key) + sizeof(aux_input) + sizeof(digest) + sizeof(sig)) {
+    return -1;
+  }
+  memcpy(priv_key, fuzzer_input(sizeof(priv_key)), sizeof(priv_key));
+  memcpy(digest, fuzzer_input(sizeof(digest)), sizeof(digest));
+  // TODO leave initialized to 0x0?
+  memcpy(aux_input, fuzzer_input(sizeof(aux_input)), sizeof(aux_input));
+  // TODO leave initialized to 0x0?
+  memcpy(sig, fuzzer_input(sizeof(sig)), sizeof(sig));
+
+  zkp_bip340_get_public_key(priv_key, pub_key);
+  check_msan(&pub_key, sizeof(pub_key));
+  zkp_bip340_sign_digest(priv_key, digest, sig, aux_input);
+  check_msan(&sig, sizeof(sig));
+  check_msan(&aux_input, sizeof(aux_input));
+
+  // IDEA test sign result?
+
+  return 0;
+}
+
+int fuzz_zkp_bip340_verify_digest(void) {
+  int res = 0;
+  uint8_t pub_key[32] = {0};
+  uint8_t digest[32] = {0};
+  uint8_t sig[64] = {0};
+
+  if (fuzzer_length < sizeof(digest) + sizeof(pub_key) + sizeof(sig)) {
+    return -1;
+  }
+  memcpy(pub_key, fuzzer_input(sizeof(pub_key)), sizeof(pub_key));
+  memcpy(digest, fuzzer_input(sizeof(digest)), sizeof(digest));
+  memcpy(sig, fuzzer_input(sizeof(sig)), sizeof(sig));
+
+  res = zkp_bip340_verify_digest(pub_key, sig, digest);
+
+  // res == 0 is valid, but crash to make successful passes visible
+  // TODO remove this later
+  if (res == 0) {
+    crash();
+  }
+
+  return 0;
+}
+
+int fuzz_zkp_bip340_tweak_keys(void) {
+  uint8_t internal_priv[32] = {0};
+  uint8_t root_hash[32] = {0};
+  uint8_t internal_pub[32] = {0};
+  uint8_t result[32] = {0};
+
+  if (fuzzer_length <
+      sizeof(internal_priv) + sizeof(root_hash) + sizeof(internal_pub)) {
+    return -1;
+  }
+  memcpy(internal_priv, fuzzer_input(sizeof(internal_priv)),
+         sizeof(internal_priv));
+  memcpy(root_hash, fuzzer_input(sizeof(root_hash)), sizeof(root_hash));
+  memcpy(internal_pub, fuzzer_input(sizeof(internal_pub)),
+         sizeof(internal_pub));
+
+  // IDEA act on return values
+  zkp_bip340_tweak_private_key(internal_priv, root_hash, result);
+  zkp_bip340_tweak_public_key(internal_pub, root_hash, result);
+
+  return 0;
+}
+
+int fuzz_ecdsa_get_public_key_functions(void) {
+  uint8_t privkey[32] = {0};
+  uint8_t pubkey33_1[33] = {0};
+  uint8_t pubkey33_2[33] = {0};
+  uint8_t pubkey65_1[65] = {0};
+  uint8_t pubkey65_2[65] = {0};
+
+  // note: the zkp_ecdsa_* variants require this specific curve
+  const ecdsa_curve *curve = &secp256k1;
+
+  if (fuzzer_length < sizeof(privkey)) {
+    return -1;
+  }
+  memcpy(privkey, fuzzer_input(sizeof(privkey)), sizeof(privkey));
+
+  int res_33_1 = ecdsa_get_public_key33(curve, privkey, pubkey33_1);
+  int res_33_2 = zkp_ecdsa_get_public_key33(curve, privkey, pubkey33_2);
+  int res_65_1 = ecdsa_get_public_key65(curve, privkey, pubkey65_1);
+  int res_65_2 = zkp_ecdsa_get_public_key65(curve, privkey, pubkey65_2);
+
+  // the function pairs have different return error codes for the same input
+  // so only fail if the one succeeds where the other does not
+  if ((res_33_1 == 0 && res_33_2 != 0) || (res_33_1 != 0 && res_33_2 == 0)) {
+    // function result mismatch
+    crash();
+  }
+  if ((res_65_1 == 0 && res_65_2 != 0) || (res_65_1 != 0 && res_65_2 == 0)) {
+    // function result mismatch
+    crash();
+  }
+
+  if (res_33_1 == 0 && res_33_2 == 0 &&
+      memcmp(&pubkey33_1, &pubkey33_2, sizeof(pubkey33_1)) != 0) {
+    // function result data mismatch
+    crash();
+  }
+
+  if (res_65_1 == 0 && res_65_2 == 0 &&
+      memcmp(&pubkey65_1, &pubkey65_2, sizeof(pubkey65_1)) != 0) {
+    // function result data mismatch
+    crash();
+  }
+
+  return 0;
+}
+
+int fuzz_ecdsa_recover_pub_from_sig_functions(void) {
+  uint8_t digest[32] = {0};
+  uint8_t sig[64] = {0};
+  const ecdsa_curve *curve = &secp256k1;
+  uint8_t recid = 0;
+  uint8_t pubkey1[65] = {0};
+  uint8_t pubkey2[65] = {0};
+
+  if (fuzzer_length < sizeof(digest) + sizeof(sig) + sizeof(recid)) {
+    return -1;
+  }
+  memcpy(digest, fuzzer_input(sizeof(digest)), sizeof(digest));
+  memcpy(sig, fuzzer_input(sizeof(sig)), sizeof(sig));
+  memcpy(&recid, fuzzer_input(sizeof(recid)), sizeof(recid));
+  // conform to parameter requirements
+  recid = recid & 0x03;
+
+  int res1 = zkp_ecdsa_recover_pub_from_sig(curve, pubkey1, sig, digest, recid);
+  int res2 = ecdsa_recover_pub_from_sig(curve, pubkey2, sig, digest, recid);
+
+  if ((res1 == 0 && res2 != 0) || (res1 != 0 && res2 == 0)) {
+    // result mismatch
+    // bug result reference: https://github.com/trezor/trezor-firmware/pull/2050
+    crash();
+  }
+
+  if (res1 == 0 && res2 == 0 &&
+      memcmp(&pubkey1, &pubkey2, sizeof(pubkey1)) != 0) {
+    // pubkey result mismatch
+    crash();
+  }
+
+  return 0;
+}
+
+int fuzz_ecdsa_sig_from_der(void) {
+  // bug result reference: https://github.com/trezor/trezor-firmware/pull/2058
+  uint8_t der[72] = {0};
+  uint8_t out[72] = {0};
+
+  if (fuzzer_length < sizeof(der)) {
+    return -1;
+  }
+  memcpy(der, fuzzer_input(sizeof(der)), sizeof(der));
+  // null-terminate
+  der[sizeof(der) - 1] = 0;
+  size_t der_len = strlen((const char *)der);
+
+  // IDEA use different fuzzer-controlled der_len such as 1 to 73
+  int ret = ecdsa_sig_from_der(der, der_len, out);
+  (void)ret;
+  // IDEA check if back conversion works
+
+  return 0;
+}
+
+int fuzz_ecdsa_sig_to_der(void) {
+  uint8_t sig[64] = {0};
+  uint8_t der[72] = {0};
+
+  if (fuzzer_length < sizeof(sig)) {
+    return -1;
+  }
+  memcpy(sig, fuzzer_input(sizeof(sig)), sizeof(sig));
+
+  int ret = ecdsa_sig_to_der((const uint8_t *)&sig, der);
+  (void)ret;
+  // IDEA check if back conversion works
+
+  return 0;
+}
+
+int fuzz_button_sequence_to_word(void) {
+  uint16_t input = 0;
+  if (fuzzer_length < sizeof(input)) {
+    return -1;
+  }
+  memcpy(&input, fuzzer_input(sizeof(input)), sizeof(input));
+
+  button_sequence_to_word(input);
+  return 0;
+}
+
+int fuzz_xmr_add_keys(void) {
+  bignum256modm a, b;
+  ge25519 A, B;
+
+  if (fuzzer_length < sizeof(bignum256modm) * 2 + sizeof(ge25519) * 2) {
+    return -1;
+  }
+  memcpy(&a, fuzzer_input(sizeof(bignum256modm)), sizeof(bignum256modm));
+  memcpy(&b, fuzzer_input(sizeof(bignum256modm)), sizeof(bignum256modm));
+  memcpy(&A, fuzzer_input(sizeof(ge25519)), sizeof(ge25519));
+  memcpy(&B, fuzzer_input(sizeof(ge25519)), sizeof(ge25519));
+
+  ge25519 r;
+
+  xmr_add_keys2(&r, a, b, &B);
+  check_msan(&r, sizeof(r));
+
+  xmr_add_keys2_vartime(&r, a, b, &B);
+  check_msan(&r, sizeof(r));
+
+  xmr_add_keys3(&r, a, &A, b, &B);
+  check_msan(&r, sizeof(r));
+
+  xmr_add_keys3_vartime(&r, a, &A, b, &B);
+  check_msan(&r, sizeof(r));
+
+  return 0;
+}
+
+int fuzz_ecdh_multiply(void) {
+  uint8_t priv_key[32];
+  // 33 or 65 bytes content
+  uint8_t pub_key[65];
+  uint8_t decider;
+  if (fuzzer_length < sizeof(priv_key) + sizeof(pub_key) + sizeof(decider)) {
+    return -1;
+  }
+  memcpy(&priv_key, fuzzer_input(sizeof(priv_key)), sizeof(priv_key));
+  memcpy(&pub_key, fuzzer_input(sizeof(pub_key)), sizeof(pub_key));
+  memcpy(&decider, fuzzer_input(sizeof(decider)), sizeof(decider));
+
+  uint8_t session_key[65] = {0};
+  int res1 = 0;
+
+  // TODO evaluate crash with &curve == NULL, documentation / convention issue?
+
+  const ecdsa_curve *curve2;
+  // ecdh_multiply() is only called with secp256k1 and nist256p1 curve from
+  // modtrezorcrypto code theoretically other curve parameters are also possible
+  if ((decider & 1) == 0) {
+    curve2 = &nist256p1;
+  } else {
+    curve2 = &secp256k1;
+  }
+
+  res1 = ecdh_multiply(curve2, (uint8_t *)&priv_key, (uint8_t *)&pub_key,
+                       (uint8_t *)&session_key);
+  check_msan(&session_key, sizeof(session_key));
+
+  if (res1 != 0) {
+    // failure case
+  }
+
+  return 0;
+}
+
+int fuzz_segwit_addr_encode(void) {
+  // the current firmware code only uses witver = 0 and witver = 1
+  // we give more flexibility, but do not allow the full int range
+  uint8_t chosen_witver = 0;
+  // restrict fuzzer variations to lengths of 0 to 255
+  uint8_t chosen_witprog_len = 0;
+
+  // in typical use, hrp is a bech32 prefix of 2 to 4 chars
+  // TODO make this dynamic, investigate lowercase requirements
+  // see also https://github.com/sipa/bech32/issues/38
+  char *hrp = "bc";
+
+  if (fuzzer_length < sizeof(chosen_witver) + sizeof(chosen_witprog_len)) {
+    return -1;
+  }
+  memcpy(&chosen_witver, fuzzer_input(sizeof(chosen_witver)),
+         sizeof(chosen_witver));
+  memcpy(&chosen_witprog_len, fuzzer_input(sizeof(chosen_witprog_len)),
+         sizeof(chosen_witprog_len));
+
+  if (chosen_witprog_len > fuzzer_length) {
+    return -1;
+  }
+
+  char output_address[MAX_ADDR_SIZE] = {0};
+  uint8_t *witprog = malloc(chosen_witprog_len);
+  RETURN_IF_NULL(witprog);
+  memcpy(witprog, fuzzer_input(chosen_witprog_len), chosen_witprog_len);
+
+  int ret = segwit_addr_encode(output_address, hrp, chosen_witver, witprog,
+                               chosen_witprog_len);
+
+  // IDEA act depending on ret
+  (void)ret;
+
+  free(witprog);
+  return 0;
+}
+
+// int segwit_addr_decode(int* witver, uint8_t* witdata, size_t* witdata_len,
+// const char* hrp, const char* addr) {
+int fuzz_segwit_addr_decode(void) {
+  int decoded_witver = 0;
+  size_t decoded_witprog_len = 0;
+  // TODO
+  uint8_t addr_raw[MAX_ADDR_RAW_SIZE] = {0};
+  uint8_t chosen_addr_len = 0;
+
+  if (fuzzer_length < sizeof(chosen_addr_len)) {
+    return -1;
+  }
+
+  memcpy(&chosen_addr_len, fuzzer_input(sizeof(chosen_addr_len)),
+         sizeof(chosen_addr_len));
+
+  if (chosen_addr_len > fuzzer_length) {
+    return -1;
+  }
+
+  char *addr = malloc(chosen_addr_len + 1);
+  RETURN_IF_NULL(addr);
+  memcpy(addr, fuzzer_input(chosen_addr_len), chosen_addr_len);
+  // null termination
+  addr[chosen_addr_len] = 0;
+
+  // TODO see comments in fuzz_segwit_addr_encode()
+  char *hrp = "bc";
+
+  int ret = segwit_addr_decode(&decoded_witver, addr_raw, &decoded_witprog_len,
+                               hrp, addr);
+  // IDEA act depending on ret
+  (void)ret;
+
+  free(addr);
+  return 0;
+}
+
+/* fuzzer main function */
+
+#define META_HEADER_SIZE 3
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+  // reject input that is too short
+  if (size < META_HEADER_SIZE) {
+    return -1;
+  }
+
+  fuzzer_reset_state();
+
+  // this controls up to 256 different test cases
+  uint8_t target_decision = data[0];
+
+  // data[1] is reserved for explicit sub decisions
+  // uint8_t target_sub_decision = data[1];
+
+  // data[2] is reserved for future use
+
+  // assign the fuzzer payload data for the target functions
+  fuzzer_ptr = data + META_HEADER_SIZE;
+  fuzzer_length = size - META_HEADER_SIZE;
+
+  // if active: reject all other inputs that are not the selected target
+  // this is helpful for directing the fuzzing focus on a specific case
+#ifdef FUZZER_EXCLUSIVE_TARGET
+  if (target_decision != FUZZER_EXCLUSIVE_TARGET) {
+    return -1;
+  }
+#endif
+
+  // recent libFuzzer implementations support marking inputs as non-interesting
+  // via return -1; instead of the regular return 0;
+  // see
+  // https://github.com/llvm/llvm-project/commit/92fb310151d2b1e349695fc0f1c5d5d50afb3b52
+  int target_result = 0;
+
+  // TODO reorder and regroup target functions
+  switch (target_decision) {
+    case 0:
+      target_result = fuzz_bn_format();
+      break;
+    case 1:
+      target_result = fuzz_base32_decode();
+      break;
+    case 2:
+      target_result = fuzz_base32_encode();
+      break;
+    case 3:
+      target_result = fuzz_base58_encode_check();
+      break;
+    case 4:
+      target_result = fuzz_base58_decode_check();
+      break;
+    case 5:
+      target_result = fuzz_xmr_base58_addr_decode_check();
+      break;
+    case 6:
+      target_result = fuzz_xmr_base58_addr_encode_check();
+      break;
+    case 7:
+      target_result = fuzz_xmr_serialize_varint();
+      break;
+    case 8:
+      target_result = fuzz_nem_validate_address();
+      break;
+    case 9:
+      target_result = fuzz_nem_get_address();
+      break;
+    case 10:
+      target_result = fuzz_xmr_get_subaddress_secret_key();
+      break;
+    case 11:
+      target_result = fuzz_xmr_derive_private_key();
+      break;
+    case 12:
+      target_result = fuzz_xmr_derive_public_key();
+      break;
+    case 13:
+      target_result = fuzz_shamir_interpolate();
+      break;
+    case 14:
+#ifdef FUZZ_ALLOW_SLOW
+      zkp_initialize_context_or_crash();
+      // slow through expensive bignum operations
+      target_result = fuzz_ecdsa_verify_digest_functions();
+#endif
+      break;
+    case 15:
+      target_result = fuzz_word_index();
+      break;
+    case 16:
+      target_result = fuzz_slip39_word_completion_mask();
+      break;
+    case 17:
+      target_result = fuzz_mnemonic_check();
+      break;
+    case 18:
+#ifdef FUZZ_ALLOW_SLOW
+      target_result = fuzz_aes();
+#endif
+      break;
+    case 22:
+      target_result = fuzz_chacha_drbg();
+      break;
+    case 23:
+#ifdef FUZZ_ALLOW_SLOW
+      zkp_initialize_context_or_crash();
+      // slow through expensive bignum operations
+      target_result = fuzz_ecdsa_sign_digest_functions();
+#endif
+      break;
+    case 24:
+      target_result = fuzz_ed25519_sign_verify();
+      break;
+    case 25:
+      target_result = fuzz_mnemonic_from_data();
+      break;
+    case 26:
+      target_result = fuzz_mnemonic_to_seed();
+      break;
+    case 27:
+      target_result = fuzz_button_sequence_to_word();
+      break;
+    case 28:
+      target_result = fuzz_segwit_addr_encode();
+      break;
+    case 29:
+      target_result = fuzz_segwit_addr_decode();
+      break;
+    case 30:
+      target_result = fuzz_ethereum_address_checksum();
+      break;
+
+    case 41:
+      zkp_initialize_context_or_crash();
+      target_result = fuzz_zkp_bip340_sign_digest();
+      break;
+    case 42:
+      zkp_initialize_context_or_crash();
+      target_result = fuzz_zkp_bip340_verify_digest();
+      break;
+    case 43:
+      zkp_initialize_context_or_crash();
+      target_result = fuzz_zkp_bip340_tweak_keys();
+      break;
+    case 50:
+      zkp_initialize_context_or_crash();
+      target_result = fuzz_ecdsa_get_public_key_functions();
+      break;
+    case 51:
+      zkp_initialize_context_or_crash();
+      target_result = fuzz_ecdsa_recover_pub_from_sig_functions();
+      break;
+    case 52:
+      target_result = fuzz_ecdsa_sig_from_der();
+      break;
+    case 53:
+      target_result = fuzz_ecdsa_sig_to_der();
+      break;
+    case 60:
+      target_result = fuzz_xmr_base58_encode();
+      break;
+    case 61:
+      target_result = fuzz_xmr_base58_decode();
+      break;
+    case 63:
+      target_result = fuzz_xmr_add_keys();
+      break;
+    case 64:
+      target_result = fuzz_ecdh_multiply();
+      break;
+
+    default:
+      // mark as uninteresting input
+      return -1;
+      break;
+  }
+  return target_result;
+}

+ 21 - 0
crypto/fuzzer/sanitizer_ignorelist.txt

@@ -0,0 +1,21 @@
+# ignore bignum math operations and other hot crypto primitives
+
+fun:*sha256_Update*
+fun:*sha256_Raw*
+fun:*sha256_Transform*
+fun:*sha512_Transform*
+fun:*pbkdf2_hmac_sha512_Update*
+fun:*pbkdf2_*
+fun:*hmac_*
+fun:*sha256_*
+# TODO this is very broad
+fun:*bn_*
+fun:*bn_inverse*
+fun:*bn_multiply*
+fun:*bn_multiply_long*
+fun:*bn_multiply_reduce_step*
+fun:*bn_multiply_step*
+fun:*curve25519_mul*
+fun:*point_multiply*
+fun:*point_jacobian_add*
+fun:*scalar_multiply*

+ 787 - 0
crypto/groestl.c

@@ -0,0 +1,787 @@
+/* Groestl hash from https://github.com/Groestlcoin/vanitygen
+ * Trezor adaptation by Yura Pakhuchiy <pakhuchiy@gmail.com>. */
+/*
+ * Groestl implementation.
+ *
+ * ==========================(LICENSE BEGIN)============================
+ *
+ * Copyright (c) 2007-2010  Projet RNRT SAPHIR
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ===========================(LICENSE END)=============================
+ *
+ * @author   Thomas Pornin <thomas.pornin@cryptolog.com>
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+#include "groestl_internal.h"
+#include "groestl.h"
+#include "memzero.h"
+
+
+#define C32e(x)     ((SPH_C32(x) >> 24) \
+                    | ((SPH_C32(x) >>  8) & SPH_C32(0x0000FF00)) \
+                    | ((SPH_C32(x) <<  8) & SPH_C32(0x00FF0000)) \
+                    | ((SPH_C32(x) << 24) & SPH_C32(0xFF000000)))
+#define dec32e_aligned   sph_dec32le_aligned
+#define enc32e           sph_enc32le
+#define B32_0(x)    ((x) & 0xFF)
+#define B32_1(x)    (((x) >> 8) & 0xFF)
+#define B32_2(x)    (((x) >> 16) & 0xFF)
+#define B32_3(x)    ((x) >> 24)
+
+#define R32u(u, d)   SPH_T32(((u) << 16) | ((d) >> 16))
+#define R32d(u, d)   SPH_T32(((u) >> 16) | ((d) << 16))
+
+#define PC32up(j, r)   ((sph_u32)((j) + (r)))
+#define PC32dn(j, r)   0
+#define QC32up(j, r)   SPH_C32(0xFFFFFFFF)
+#define QC32dn(j, r)   (((sph_u32)(r) << 24) ^ SPH_T32(~((sph_u32)(j) << 24)))
+
+#define C64e(x)     ((SPH_C64(x) >> 56) \
+                    | ((SPH_C64(x) >> 40) & SPH_C64(0x000000000000FF00)) \
+                    | ((SPH_C64(x) >> 24) & SPH_C64(0x0000000000FF0000)) \
+                    | ((SPH_C64(x) >>  8) & SPH_C64(0x00000000FF000000)) \
+                    | ((SPH_C64(x) <<  8) & SPH_C64(0x000000FF00000000)) \
+                    | ((SPH_C64(x) << 24) & SPH_C64(0x0000FF0000000000)) \
+                    | ((SPH_C64(x) << 40) & SPH_C64(0x00FF000000000000)) \
+                    | ((SPH_C64(x) << 56) & SPH_C64(0xFF00000000000000)))
+#define dec64e_aligned   sph_dec64le_aligned
+#define enc64e           sph_enc64le
+#define B64_0(x)    ((x) & 0xFF)
+#define B64_1(x)    (((x) >> 8) & 0xFF)
+#define B64_2(x)    (((x) >> 16) & 0xFF)
+#define B64_3(x)    (((x) >> 24) & 0xFF)
+#define B64_4(x)    (((x) >> 32) & 0xFF)
+#define B64_5(x)    (((x) >> 40) & 0xFF)
+#define B64_6(x)    (((x) >> 48) & 0xFF)
+#define B64_7(x)    ((x) >> 56)
+#define R64         SPH_ROTL64
+#define PC64(j, r)  ((sph_u64)((j) + (r)))
+#define QC64(j, r)  (((sph_u64)(r) << 56) ^ SPH_T64(~((sph_u64)(j) << 56)))
+
+
+static const sph_u32 T0up[] = {
+	C32e(0xc632f4a5), C32e(0xf86f9784), C32e(0xee5eb099), C32e(0xf67a8c8d),
+	C32e(0xffe8170d), C32e(0xd60adcbd), C32e(0xde16c8b1), C32e(0x916dfc54),
+	C32e(0x6090f050), C32e(0x02070503), C32e(0xce2ee0a9), C32e(0x56d1877d),
+	C32e(0xe7cc2b19), C32e(0xb513a662), C32e(0x4d7c31e6), C32e(0xec59b59a),
+	C32e(0x8f40cf45), C32e(0x1fa3bc9d), C32e(0x8949c040), C32e(0xfa689287),
+	C32e(0xefd03f15), C32e(0xb29426eb), C32e(0x8ece40c9), C32e(0xfbe61d0b),
+	C32e(0x416e2fec), C32e(0xb31aa967), C32e(0x5f431cfd), C32e(0x456025ea),
+	C32e(0x23f9dabf), C32e(0x535102f7), C32e(0xe445a196), C32e(0x9b76ed5b),
+	C32e(0x75285dc2), C32e(0xe1c5241c), C32e(0x3dd4e9ae), C32e(0x4cf2be6a),
+	C32e(0x6c82ee5a), C32e(0x7ebdc341), C32e(0xf5f30602), C32e(0x8352d14f),
+	C32e(0x688ce45c), C32e(0x515607f4), C32e(0xd18d5c34), C32e(0xf9e11808),
+	C32e(0xe24cae93), C32e(0xab3e9573), C32e(0x6297f553), C32e(0x2a6b413f),
+	C32e(0x081c140c), C32e(0x9563f652), C32e(0x46e9af65), C32e(0x9d7fe25e),
+	C32e(0x30487828), C32e(0x37cff8a1), C32e(0x0a1b110f), C32e(0x2febc4b5),
+	C32e(0x0e151b09), C32e(0x247e5a36), C32e(0x1badb69b), C32e(0xdf98473d),
+	C32e(0xcda76a26), C32e(0x4ef5bb69), C32e(0x7f334ccd), C32e(0xea50ba9f),
+	C32e(0x123f2d1b), C32e(0x1da4b99e), C32e(0x58c49c74), C32e(0x3446722e),
+	C32e(0x3641772d), C32e(0xdc11cdb2), C32e(0xb49d29ee), C32e(0x5b4d16fb),
+	C32e(0xa4a501f6), C32e(0x76a1d74d), C32e(0xb714a361), C32e(0x7d3449ce),
+	C32e(0x52df8d7b), C32e(0xdd9f423e), C32e(0x5ecd9371), C32e(0x13b1a297),
+	C32e(0xa6a204f5), C32e(0xb901b868), C32e(0x00000000), C32e(0xc1b5742c),
+	C32e(0x40e0a060), C32e(0xe3c2211f), C32e(0x793a43c8), C32e(0xb69a2ced),
+	C32e(0xd40dd9be), C32e(0x8d47ca46), C32e(0x671770d9), C32e(0x72afdd4b),
+	C32e(0x94ed79de), C32e(0x98ff67d4), C32e(0xb09323e8), C32e(0x855bde4a),
+	C32e(0xbb06bd6b), C32e(0xc5bb7e2a), C32e(0x4f7b34e5), C32e(0xedd73a16),
+	C32e(0x86d254c5), C32e(0x9af862d7), C32e(0x6699ff55), C32e(0x11b6a794),
+	C32e(0x8ac04acf), C32e(0xe9d93010), C32e(0x040e0a06), C32e(0xfe669881),
+	C32e(0xa0ab0bf0), C32e(0x78b4cc44), C32e(0x25f0d5ba), C32e(0x4b753ee3),
+	C32e(0xa2ac0ef3), C32e(0x5d4419fe), C32e(0x80db5bc0), C32e(0x0580858a),
+	C32e(0x3fd3ecad), C32e(0x21fedfbc), C32e(0x70a8d848), C32e(0xf1fd0c04),
+	C32e(0x63197adf), C32e(0x772f58c1), C32e(0xaf309f75), C32e(0x42e7a563),
+	C32e(0x20705030), C32e(0xe5cb2e1a), C32e(0xfdef120e), C32e(0xbf08b76d),
+	C32e(0x8155d44c), C32e(0x18243c14), C32e(0x26795f35), C32e(0xc3b2712f),
+	C32e(0xbe8638e1), C32e(0x35c8fda2), C32e(0x88c74fcc), C32e(0x2e654b39),
+	C32e(0x936af957), C32e(0x55580df2), C32e(0xfc619d82), C32e(0x7ab3c947),
+	C32e(0xc827efac), C32e(0xba8832e7), C32e(0x324f7d2b), C32e(0xe642a495),
+	C32e(0xc03bfba0), C32e(0x19aab398), C32e(0x9ef668d1), C32e(0xa322817f),
+	C32e(0x44eeaa66), C32e(0x54d6827e), C32e(0x3bdde6ab), C32e(0x0b959e83),
+	C32e(0x8cc945ca), C32e(0xc7bc7b29), C32e(0x6b056ed3), C32e(0x286c443c),
+	C32e(0xa72c8b79), C32e(0xbc813de2), C32e(0x1631271d), C32e(0xad379a76),
+	C32e(0xdb964d3b), C32e(0x649efa56), C32e(0x74a6d24e), C32e(0x1436221e),
+	C32e(0x92e476db), C32e(0x0c121e0a), C32e(0x48fcb46c), C32e(0xb88f37e4),
+	C32e(0x9f78e75d), C32e(0xbd0fb26e), C32e(0x43692aef), C32e(0xc435f1a6),
+	C32e(0x39dae3a8), C32e(0x31c6f7a4), C32e(0xd38a5937), C32e(0xf274868b),
+	C32e(0xd5835632), C32e(0x8b4ec543), C32e(0x6e85eb59), C32e(0xda18c2b7),
+	C32e(0x018e8f8c), C32e(0xb11dac64), C32e(0x9cf16dd2), C32e(0x49723be0),
+	C32e(0xd81fc7b4), C32e(0xacb915fa), C32e(0xf3fa0907), C32e(0xcfa06f25),
+	C32e(0xca20eaaf), C32e(0xf47d898e), C32e(0x476720e9), C32e(0x10382818),
+	C32e(0x6f0b64d5), C32e(0xf0738388), C32e(0x4afbb16f), C32e(0x5cca9672),
+	C32e(0x38546c24), C32e(0x575f08f1), C32e(0x732152c7), C32e(0x9764f351),
+	C32e(0xcbae6523), C32e(0xa125847c), C32e(0xe857bf9c), C32e(0x3e5d6321),
+	C32e(0x96ea7cdd), C32e(0x611e7fdc), C32e(0x0d9c9186), C32e(0x0f9b9485),
+	C32e(0xe04bab90), C32e(0x7cbac642), C32e(0x712657c4), C32e(0xcc29e5aa),
+	C32e(0x90e373d8), C32e(0x06090f05), C32e(0xf7f40301), C32e(0x1c2a3612),
+	C32e(0xc23cfea3), C32e(0x6a8be15f), C32e(0xaebe10f9), C32e(0x69026bd0),
+	C32e(0x17bfa891), C32e(0x9971e858), C32e(0x3a536927), C32e(0x27f7d0b9),
+	C32e(0xd9914838), C32e(0xebde3513), C32e(0x2be5ceb3), C32e(0x22775533),
+	C32e(0xd204d6bb), C32e(0xa9399070), C32e(0x07878089), C32e(0x33c1f2a7),
+	C32e(0x2decc1b6), C32e(0x3c5a6622), C32e(0x15b8ad92), C32e(0xc9a96020),
+	C32e(0x875cdb49), C32e(0xaab01aff), C32e(0x50d88878), C32e(0xa52b8e7a),
+	C32e(0x03898a8f), C32e(0x594a13f8), C32e(0x09929b80), C32e(0x1a233917),
+	C32e(0x651075da), C32e(0xd7845331), C32e(0x84d551c6), C32e(0xd003d3b8),
+	C32e(0x82dc5ec3), C32e(0x29e2cbb0), C32e(0x5ac39977), C32e(0x1e2d3311),
+	C32e(0x7b3d46cb), C32e(0xa8b71ffc), C32e(0x6d0c61d6), C32e(0x2c624e3a)
+};
+
+static const sph_u32 T0dn[] = {
+	C32e(0xf497a5c6), C32e(0x97eb84f8), C32e(0xb0c799ee), C32e(0x8cf78df6),
+	C32e(0x17e50dff), C32e(0xdcb7bdd6), C32e(0xc8a7b1de), C32e(0xfc395491),
+	C32e(0xf0c05060), C32e(0x05040302), C32e(0xe087a9ce), C32e(0x87ac7d56),
+	C32e(0x2bd519e7), C32e(0xa67162b5), C32e(0x319ae64d), C32e(0xb5c39aec),
+	C32e(0xcf05458f), C32e(0xbc3e9d1f), C32e(0xc0094089), C32e(0x92ef87fa),
+	C32e(0x3fc515ef), C32e(0x267febb2), C32e(0x4007c98e), C32e(0x1ded0bfb),
+	C32e(0x2f82ec41), C32e(0xa97d67b3), C32e(0x1cbefd5f), C32e(0x258aea45),
+	C32e(0xda46bf23), C32e(0x02a6f753), C32e(0xa1d396e4), C32e(0xed2d5b9b),
+	C32e(0x5deac275), C32e(0x24d91ce1), C32e(0xe97aae3d), C32e(0xbe986a4c),
+	C32e(0xeed85a6c), C32e(0xc3fc417e), C32e(0x06f102f5), C32e(0xd11d4f83),
+	C32e(0xe4d05c68), C32e(0x07a2f451), C32e(0x5cb934d1), C32e(0x18e908f9),
+	C32e(0xaedf93e2), C32e(0x954d73ab), C32e(0xf5c45362), C32e(0x41543f2a),
+	C32e(0x14100c08), C32e(0xf6315295), C32e(0xaf8c6546), C32e(0xe2215e9d),
+	C32e(0x78602830), C32e(0xf86ea137), C32e(0x11140f0a), C32e(0xc45eb52f),
+	C32e(0x1b1c090e), C32e(0x5a483624), C32e(0xb6369b1b), C32e(0x47a53ddf),
+	C32e(0x6a8126cd), C32e(0xbb9c694e), C32e(0x4cfecd7f), C32e(0xbacf9fea),
+	C32e(0x2d241b12), C32e(0xb93a9e1d), C32e(0x9cb07458), C32e(0x72682e34),
+	C32e(0x776c2d36), C32e(0xcda3b2dc), C32e(0x2973eeb4), C32e(0x16b6fb5b),
+	C32e(0x0153f6a4), C32e(0xd7ec4d76), C32e(0xa37561b7), C32e(0x49face7d),
+	C32e(0x8da47b52), C32e(0x42a13edd), C32e(0x93bc715e), C32e(0xa2269713),
+	C32e(0x0457f5a6), C32e(0xb86968b9), C32e(0x00000000), C32e(0x74992cc1),
+	C32e(0xa0806040), C32e(0x21dd1fe3), C32e(0x43f2c879), C32e(0x2c77edb6),
+	C32e(0xd9b3bed4), C32e(0xca01468d), C32e(0x70ced967), C32e(0xdde44b72),
+	C32e(0x7933de94), C32e(0x672bd498), C32e(0x237be8b0), C32e(0xde114a85),
+	C32e(0xbd6d6bbb), C32e(0x7e912ac5), C32e(0x349ee54f), C32e(0x3ac116ed),
+	C32e(0x5417c586), C32e(0x622fd79a), C32e(0xffcc5566), C32e(0xa7229411),
+	C32e(0x4a0fcf8a), C32e(0x30c910e9), C32e(0x0a080604), C32e(0x98e781fe),
+	C32e(0x0b5bf0a0), C32e(0xccf04478), C32e(0xd54aba25), C32e(0x3e96e34b),
+	C32e(0x0e5ff3a2), C32e(0x19bafe5d), C32e(0x5b1bc080), C32e(0x850a8a05),
+	C32e(0xec7ead3f), C32e(0xdf42bc21), C32e(0xd8e04870), C32e(0x0cf904f1),
+	C32e(0x7ac6df63), C32e(0x58eec177), C32e(0x9f4575af), C32e(0xa5846342),
+	C32e(0x50403020), C32e(0x2ed11ae5), C32e(0x12e10efd), C32e(0xb7656dbf),
+	C32e(0xd4194c81), C32e(0x3c301418), C32e(0x5f4c3526), C32e(0x719d2fc3),
+	C32e(0x3867e1be), C32e(0xfd6aa235), C32e(0x4f0bcc88), C32e(0x4b5c392e),
+	C32e(0xf93d5793), C32e(0x0daaf255), C32e(0x9de382fc), C32e(0xc9f4477a),
+	C32e(0xef8bacc8), C32e(0x326fe7ba), C32e(0x7d642b32), C32e(0xa4d795e6),
+	C32e(0xfb9ba0c0), C32e(0xb3329819), C32e(0x6827d19e), C32e(0x815d7fa3),
+	C32e(0xaa886644), C32e(0x82a87e54), C32e(0xe676ab3b), C32e(0x9e16830b),
+	C32e(0x4503ca8c), C32e(0x7b9529c7), C32e(0x6ed6d36b), C32e(0x44503c28),
+	C32e(0x8b5579a7), C32e(0x3d63e2bc), C32e(0x272c1d16), C32e(0x9a4176ad),
+	C32e(0x4dad3bdb), C32e(0xfac85664), C32e(0xd2e84e74), C32e(0x22281e14),
+	C32e(0x763fdb92), C32e(0x1e180a0c), C32e(0xb4906c48), C32e(0x376be4b8),
+	C32e(0xe7255d9f), C32e(0xb2616ebd), C32e(0x2a86ef43), C32e(0xf193a6c4),
+	C32e(0xe372a839), C32e(0xf762a431), C32e(0x59bd37d3), C32e(0x86ff8bf2),
+	C32e(0x56b132d5), C32e(0xc50d438b), C32e(0xebdc596e), C32e(0xc2afb7da),
+	C32e(0x8f028c01), C32e(0xac7964b1), C32e(0x6d23d29c), C32e(0x3b92e049),
+	C32e(0xc7abb4d8), C32e(0x1543faac), C32e(0x09fd07f3), C32e(0x6f8525cf),
+	C32e(0xea8fafca), C32e(0x89f38ef4), C32e(0x208ee947), C32e(0x28201810),
+	C32e(0x64ded56f), C32e(0x83fb88f0), C32e(0xb1946f4a), C32e(0x96b8725c),
+	C32e(0x6c702438), C32e(0x08aef157), C32e(0x52e6c773), C32e(0xf3355197),
+	C32e(0x658d23cb), C32e(0x84597ca1), C32e(0xbfcb9ce8), C32e(0x637c213e),
+	C32e(0x7c37dd96), C32e(0x7fc2dc61), C32e(0x911a860d), C32e(0x941e850f),
+	C32e(0xabdb90e0), C32e(0xc6f8427c), C32e(0x57e2c471), C32e(0xe583aacc),
+	C32e(0x733bd890), C32e(0x0f0c0506), C32e(0x03f501f7), C32e(0x3638121c),
+	C32e(0xfe9fa3c2), C32e(0xe1d45f6a), C32e(0x1047f9ae), C32e(0x6bd2d069),
+	C32e(0xa82e9117), C32e(0xe8295899), C32e(0x6974273a), C32e(0xd04eb927),
+	C32e(0x48a938d9), C32e(0x35cd13eb), C32e(0xce56b32b), C32e(0x55443322),
+	C32e(0xd6bfbbd2), C32e(0x904970a9), C32e(0x800e8907), C32e(0xf266a733),
+	C32e(0xc15ab62d), C32e(0x6678223c), C32e(0xad2a9215), C32e(0x608920c9),
+	C32e(0xdb154987), C32e(0x1a4fffaa), C32e(0x88a07850), C32e(0x8e517aa5),
+	C32e(0x8a068f03), C32e(0x13b2f859), C32e(0x9b128009), C32e(0x3934171a),
+	C32e(0x75cada65), C32e(0x53b531d7), C32e(0x5113c684), C32e(0xd3bbb8d0),
+	C32e(0x5e1fc382), C32e(0xcb52b029), C32e(0x99b4775a), C32e(0x333c111e),
+	C32e(0x46f6cb7b), C32e(0x1f4bfca8), C32e(0x61dad66d), C32e(0x4e583a2c)
+};
+
+static const sph_u32 T1up[] = {
+	C32e(0xc6c632f4), C32e(0xf8f86f97), C32e(0xeeee5eb0), C32e(0xf6f67a8c),
+	C32e(0xffffe817), C32e(0xd6d60adc), C32e(0xdede16c8), C32e(0x91916dfc),
+	C32e(0x606090f0), C32e(0x02020705), C32e(0xcece2ee0), C32e(0x5656d187),
+	C32e(0xe7e7cc2b), C32e(0xb5b513a6), C32e(0x4d4d7c31), C32e(0xecec59b5),
+	C32e(0x8f8f40cf), C32e(0x1f1fa3bc), C32e(0x898949c0), C32e(0xfafa6892),
+	C32e(0xefefd03f), C32e(0xb2b29426), C32e(0x8e8ece40), C32e(0xfbfbe61d),
+	C32e(0x41416e2f), C32e(0xb3b31aa9), C32e(0x5f5f431c), C32e(0x45456025),
+	C32e(0x2323f9da), C32e(0x53535102), C32e(0xe4e445a1), C32e(0x9b9b76ed),
+	C32e(0x7575285d), C32e(0xe1e1c524), C32e(0x3d3dd4e9), C32e(0x4c4cf2be),
+	C32e(0x6c6c82ee), C32e(0x7e7ebdc3), C32e(0xf5f5f306), C32e(0x838352d1),
+	C32e(0x68688ce4), C32e(0x51515607), C32e(0xd1d18d5c), C32e(0xf9f9e118),
+	C32e(0xe2e24cae), C32e(0xabab3e95), C32e(0x626297f5), C32e(0x2a2a6b41),
+	C32e(0x08081c14), C32e(0x959563f6), C32e(0x4646e9af), C32e(0x9d9d7fe2),
+	C32e(0x30304878), C32e(0x3737cff8), C32e(0x0a0a1b11), C32e(0x2f2febc4),
+	C32e(0x0e0e151b), C32e(0x24247e5a), C32e(0x1b1badb6), C32e(0xdfdf9847),
+	C32e(0xcdcda76a), C32e(0x4e4ef5bb), C32e(0x7f7f334c), C32e(0xeaea50ba),
+	C32e(0x12123f2d), C32e(0x1d1da4b9), C32e(0x5858c49c), C32e(0x34344672),
+	C32e(0x36364177), C32e(0xdcdc11cd), C32e(0xb4b49d29), C32e(0x5b5b4d16),
+	C32e(0xa4a4a501), C32e(0x7676a1d7), C32e(0xb7b714a3), C32e(0x7d7d3449),
+	C32e(0x5252df8d), C32e(0xdddd9f42), C32e(0x5e5ecd93), C32e(0x1313b1a2),
+	C32e(0xa6a6a204), C32e(0xb9b901b8), C32e(0x00000000), C32e(0xc1c1b574),
+	C32e(0x4040e0a0), C32e(0xe3e3c221), C32e(0x79793a43), C32e(0xb6b69a2c),
+	C32e(0xd4d40dd9), C32e(0x8d8d47ca), C32e(0x67671770), C32e(0x7272afdd),
+	C32e(0x9494ed79), C32e(0x9898ff67), C32e(0xb0b09323), C32e(0x85855bde),
+	C32e(0xbbbb06bd), C32e(0xc5c5bb7e), C32e(0x4f4f7b34), C32e(0xededd73a),
+	C32e(0x8686d254), C32e(0x9a9af862), C32e(0x666699ff), C32e(0x1111b6a7),
+	C32e(0x8a8ac04a), C32e(0xe9e9d930), C32e(0x04040e0a), C32e(0xfefe6698),
+	C32e(0xa0a0ab0b), C32e(0x7878b4cc), C32e(0x2525f0d5), C32e(0x4b4b753e),
+	C32e(0xa2a2ac0e), C32e(0x5d5d4419), C32e(0x8080db5b), C32e(0x05058085),
+	C32e(0x3f3fd3ec), C32e(0x2121fedf), C32e(0x7070a8d8), C32e(0xf1f1fd0c),
+	C32e(0x6363197a), C32e(0x77772f58), C32e(0xafaf309f), C32e(0x4242e7a5),
+	C32e(0x20207050), C32e(0xe5e5cb2e), C32e(0xfdfdef12), C32e(0xbfbf08b7),
+	C32e(0x818155d4), C32e(0x1818243c), C32e(0x2626795f), C32e(0xc3c3b271),
+	C32e(0xbebe8638), C32e(0x3535c8fd), C32e(0x8888c74f), C32e(0x2e2e654b),
+	C32e(0x93936af9), C32e(0x5555580d), C32e(0xfcfc619d), C32e(0x7a7ab3c9),
+	C32e(0xc8c827ef), C32e(0xbaba8832), C32e(0x32324f7d), C32e(0xe6e642a4),
+	C32e(0xc0c03bfb), C32e(0x1919aab3), C32e(0x9e9ef668), C32e(0xa3a32281),
+	C32e(0x4444eeaa), C32e(0x5454d682), C32e(0x3b3bdde6), C32e(0x0b0b959e),
+	C32e(0x8c8cc945), C32e(0xc7c7bc7b), C32e(0x6b6b056e), C32e(0x28286c44),
+	C32e(0xa7a72c8b), C32e(0xbcbc813d), C32e(0x16163127), C32e(0xadad379a),
+	C32e(0xdbdb964d), C32e(0x64649efa), C32e(0x7474a6d2), C32e(0x14143622),
+	C32e(0x9292e476), C32e(0x0c0c121e), C32e(0x4848fcb4), C32e(0xb8b88f37),
+	C32e(0x9f9f78e7), C32e(0xbdbd0fb2), C32e(0x4343692a), C32e(0xc4c435f1),
+	C32e(0x3939dae3), C32e(0x3131c6f7), C32e(0xd3d38a59), C32e(0xf2f27486),
+	C32e(0xd5d58356), C32e(0x8b8b4ec5), C32e(0x6e6e85eb), C32e(0xdada18c2),
+	C32e(0x01018e8f), C32e(0xb1b11dac), C32e(0x9c9cf16d), C32e(0x4949723b),
+	C32e(0xd8d81fc7), C32e(0xacacb915), C32e(0xf3f3fa09), C32e(0xcfcfa06f),
+	C32e(0xcaca20ea), C32e(0xf4f47d89), C32e(0x47476720), C32e(0x10103828),
+	C32e(0x6f6f0b64), C32e(0xf0f07383), C32e(0x4a4afbb1), C32e(0x5c5cca96),
+	C32e(0x3838546c), C32e(0x57575f08), C32e(0x73732152), C32e(0x979764f3),
+	C32e(0xcbcbae65), C32e(0xa1a12584), C32e(0xe8e857bf), C32e(0x3e3e5d63),
+	C32e(0x9696ea7c), C32e(0x61611e7f), C32e(0x0d0d9c91), C32e(0x0f0f9b94),
+	C32e(0xe0e04bab), C32e(0x7c7cbac6), C32e(0x71712657), C32e(0xcccc29e5),
+	C32e(0x9090e373), C32e(0x0606090f), C32e(0xf7f7f403), C32e(0x1c1c2a36),
+	C32e(0xc2c23cfe), C32e(0x6a6a8be1), C32e(0xaeaebe10), C32e(0x6969026b),
+	C32e(0x1717bfa8), C32e(0x999971e8), C32e(0x3a3a5369), C32e(0x2727f7d0),
+	C32e(0xd9d99148), C32e(0xebebde35), C32e(0x2b2be5ce), C32e(0x22227755),
+	C32e(0xd2d204d6), C32e(0xa9a93990), C32e(0x07078780), C32e(0x3333c1f2),
+	C32e(0x2d2decc1), C32e(0x3c3c5a66), C32e(0x1515b8ad), C32e(0xc9c9a960),
+	C32e(0x87875cdb), C32e(0xaaaab01a), C32e(0x5050d888), C32e(0xa5a52b8e),
+	C32e(0x0303898a), C32e(0x59594a13), C32e(0x0909929b), C32e(0x1a1a2339),
+	C32e(0x65651075), C32e(0xd7d78453), C32e(0x8484d551), C32e(0xd0d003d3),
+	C32e(0x8282dc5e), C32e(0x2929e2cb), C32e(0x5a5ac399), C32e(0x1e1e2d33),
+	C32e(0x7b7b3d46), C32e(0xa8a8b71f), C32e(0x6d6d0c61), C32e(0x2c2c624e)
+};
+
+static const sph_u32 T1dn[] = {
+	C32e(0xa5f497a5), C32e(0x8497eb84), C32e(0x99b0c799), C32e(0x8d8cf78d),
+	C32e(0x0d17e50d), C32e(0xbddcb7bd), C32e(0xb1c8a7b1), C32e(0x54fc3954),
+	C32e(0x50f0c050), C32e(0x03050403), C32e(0xa9e087a9), C32e(0x7d87ac7d),
+	C32e(0x192bd519), C32e(0x62a67162), C32e(0xe6319ae6), C32e(0x9ab5c39a),
+	C32e(0x45cf0545), C32e(0x9dbc3e9d), C32e(0x40c00940), C32e(0x8792ef87),
+	C32e(0x153fc515), C32e(0xeb267feb), C32e(0xc94007c9), C32e(0x0b1ded0b),
+	C32e(0xec2f82ec), C32e(0x67a97d67), C32e(0xfd1cbefd), C32e(0xea258aea),
+	C32e(0xbfda46bf), C32e(0xf702a6f7), C32e(0x96a1d396), C32e(0x5bed2d5b),
+	C32e(0xc25deac2), C32e(0x1c24d91c), C32e(0xaee97aae), C32e(0x6abe986a),
+	C32e(0x5aeed85a), C32e(0x41c3fc41), C32e(0x0206f102), C32e(0x4fd11d4f),
+	C32e(0x5ce4d05c), C32e(0xf407a2f4), C32e(0x345cb934), C32e(0x0818e908),
+	C32e(0x93aedf93), C32e(0x73954d73), C32e(0x53f5c453), C32e(0x3f41543f),
+	C32e(0x0c14100c), C32e(0x52f63152), C32e(0x65af8c65), C32e(0x5ee2215e),
+	C32e(0x28786028), C32e(0xa1f86ea1), C32e(0x0f11140f), C32e(0xb5c45eb5),
+	C32e(0x091b1c09), C32e(0x365a4836), C32e(0x9bb6369b), C32e(0x3d47a53d),
+	C32e(0x266a8126), C32e(0x69bb9c69), C32e(0xcd4cfecd), C32e(0x9fbacf9f),
+	C32e(0x1b2d241b), C32e(0x9eb93a9e), C32e(0x749cb074), C32e(0x2e72682e),
+	C32e(0x2d776c2d), C32e(0xb2cda3b2), C32e(0xee2973ee), C32e(0xfb16b6fb),
+	C32e(0xf60153f6), C32e(0x4dd7ec4d), C32e(0x61a37561), C32e(0xce49face),
+	C32e(0x7b8da47b), C32e(0x3e42a13e), C32e(0x7193bc71), C32e(0x97a22697),
+	C32e(0xf50457f5), C32e(0x68b86968), C32e(0x00000000), C32e(0x2c74992c),
+	C32e(0x60a08060), C32e(0x1f21dd1f), C32e(0xc843f2c8), C32e(0xed2c77ed),
+	C32e(0xbed9b3be), C32e(0x46ca0146), C32e(0xd970ced9), C32e(0x4bdde44b),
+	C32e(0xde7933de), C32e(0xd4672bd4), C32e(0xe8237be8), C32e(0x4ade114a),
+	C32e(0x6bbd6d6b), C32e(0x2a7e912a), C32e(0xe5349ee5), C32e(0x163ac116),
+	C32e(0xc55417c5), C32e(0xd7622fd7), C32e(0x55ffcc55), C32e(0x94a72294),
+	C32e(0xcf4a0fcf), C32e(0x1030c910), C32e(0x060a0806), C32e(0x8198e781),
+	C32e(0xf00b5bf0), C32e(0x44ccf044), C32e(0xbad54aba), C32e(0xe33e96e3),
+	C32e(0xf30e5ff3), C32e(0xfe19bafe), C32e(0xc05b1bc0), C32e(0x8a850a8a),
+	C32e(0xadec7ead), C32e(0xbcdf42bc), C32e(0x48d8e048), C32e(0x040cf904),
+	C32e(0xdf7ac6df), C32e(0xc158eec1), C32e(0x759f4575), C32e(0x63a58463),
+	C32e(0x30504030), C32e(0x1a2ed11a), C32e(0x0e12e10e), C32e(0x6db7656d),
+	C32e(0x4cd4194c), C32e(0x143c3014), C32e(0x355f4c35), C32e(0x2f719d2f),
+	C32e(0xe13867e1), C32e(0xa2fd6aa2), C32e(0xcc4f0bcc), C32e(0x394b5c39),
+	C32e(0x57f93d57), C32e(0xf20daaf2), C32e(0x829de382), C32e(0x47c9f447),
+	C32e(0xacef8bac), C32e(0xe7326fe7), C32e(0x2b7d642b), C32e(0x95a4d795),
+	C32e(0xa0fb9ba0), C32e(0x98b33298), C32e(0xd16827d1), C32e(0x7f815d7f),
+	C32e(0x66aa8866), C32e(0x7e82a87e), C32e(0xabe676ab), C32e(0x839e1683),
+	C32e(0xca4503ca), C32e(0x297b9529), C32e(0xd36ed6d3), C32e(0x3c44503c),
+	C32e(0x798b5579), C32e(0xe23d63e2), C32e(0x1d272c1d), C32e(0x769a4176),
+	C32e(0x3b4dad3b), C32e(0x56fac856), C32e(0x4ed2e84e), C32e(0x1e22281e),
+	C32e(0xdb763fdb), C32e(0x0a1e180a), C32e(0x6cb4906c), C32e(0xe4376be4),
+	C32e(0x5de7255d), C32e(0x6eb2616e), C32e(0xef2a86ef), C32e(0xa6f193a6),
+	C32e(0xa8e372a8), C32e(0xa4f762a4), C32e(0x3759bd37), C32e(0x8b86ff8b),
+	C32e(0x3256b132), C32e(0x43c50d43), C32e(0x59ebdc59), C32e(0xb7c2afb7),
+	C32e(0x8c8f028c), C32e(0x64ac7964), C32e(0xd26d23d2), C32e(0xe03b92e0),
+	C32e(0xb4c7abb4), C32e(0xfa1543fa), C32e(0x0709fd07), C32e(0x256f8525),
+	C32e(0xafea8faf), C32e(0x8e89f38e), C32e(0xe9208ee9), C32e(0x18282018),
+	C32e(0xd564ded5), C32e(0x8883fb88), C32e(0x6fb1946f), C32e(0x7296b872),
+	C32e(0x246c7024), C32e(0xf108aef1), C32e(0xc752e6c7), C32e(0x51f33551),
+	C32e(0x23658d23), C32e(0x7c84597c), C32e(0x9cbfcb9c), C32e(0x21637c21),
+	C32e(0xdd7c37dd), C32e(0xdc7fc2dc), C32e(0x86911a86), C32e(0x85941e85),
+	C32e(0x90abdb90), C32e(0x42c6f842), C32e(0xc457e2c4), C32e(0xaae583aa),
+	C32e(0xd8733bd8), C32e(0x050f0c05), C32e(0x0103f501), C32e(0x12363812),
+	C32e(0xa3fe9fa3), C32e(0x5fe1d45f), C32e(0xf91047f9), C32e(0xd06bd2d0),
+	C32e(0x91a82e91), C32e(0x58e82958), C32e(0x27697427), C32e(0xb9d04eb9),
+	C32e(0x3848a938), C32e(0x1335cd13), C32e(0xb3ce56b3), C32e(0x33554433),
+	C32e(0xbbd6bfbb), C32e(0x70904970), C32e(0x89800e89), C32e(0xa7f266a7),
+	C32e(0xb6c15ab6), C32e(0x22667822), C32e(0x92ad2a92), C32e(0x20608920),
+	C32e(0x49db1549), C32e(0xff1a4fff), C32e(0x7888a078), C32e(0x7a8e517a),
+	C32e(0x8f8a068f), C32e(0xf813b2f8), C32e(0x809b1280), C32e(0x17393417),
+	C32e(0xda75cada), C32e(0x3153b531), C32e(0xc65113c6), C32e(0xb8d3bbb8),
+	C32e(0xc35e1fc3), C32e(0xb0cb52b0), C32e(0x7799b477), C32e(0x11333c11),
+	C32e(0xcb46f6cb), C32e(0xfc1f4bfc), C32e(0xd661dad6), C32e(0x3a4e583a)
+};
+
+#define DECL_STATE_SMALL \
+	sph_u32 H[16] = {0};
+
+#define READ_STATE_SMALL(sc)   do { \
+		memcpy(H, (sc)->state.narrow, sizeof H); \
+	} while (0)
+
+#define WRITE_STATE_SMALL(sc)   do { \
+		memcpy((sc)->state.narrow, H, sizeof H); \
+	} while (0)
+
+#define XCAT(x, y)    XCAT_(x, y)
+#define XCAT_(x, y)   x ## y
+
+#define RSTT(d0, d1, a, b0, b1, b2, b3, b4, b5, b6, b7)   do { \
+		t[d0] = T0up[B32_0(a[b0])] \
+			^ T1up[B32_1(a[b1])] \
+			^ T2up[B32_2(a[b2])] \
+			^ T3up[B32_3(a[b3])] \
+			^ T0dn[B32_0(a[b4])] \
+			^ T1dn[B32_1(a[b5])] \
+			^ T2dn[B32_2(a[b6])] \
+			^ T3dn[B32_3(a[b7])]; \
+		t[d1] = T0dn[B32_0(a[b0])] \
+			^ T1dn[B32_1(a[b1])] \
+			^ T2dn[B32_2(a[b2])] \
+			^ T3dn[B32_3(a[b3])] \
+			^ T0up[B32_0(a[b4])] \
+			^ T1up[B32_1(a[b5])] \
+			^ T2up[B32_2(a[b6])] \
+			^ T3up[B32_3(a[b7])]; \
+	} while (0)
+
+#define ROUND_SMALL_P(a, r)   do { \
+		sph_u32 t[16]; \
+		a[0x0] ^= PC32up(0x00, r); \
+		a[0x1] ^= PC32dn(0x00, r); \
+		a[0x2] ^= PC32up(0x10, r); \
+		a[0x3] ^= PC32dn(0x10, r); \
+		a[0x4] ^= PC32up(0x20, r); \
+		a[0x5] ^= PC32dn(0x20, r); \
+		a[0x6] ^= PC32up(0x30, r); \
+		a[0x7] ^= PC32dn(0x30, r); \
+		a[0x8] ^= PC32up(0x40, r); \
+		a[0x9] ^= PC32dn(0x40, r); \
+		a[0xA] ^= PC32up(0x50, r); \
+		a[0xB] ^= PC32dn(0x50, r); \
+		a[0xC] ^= PC32up(0x60, r); \
+		a[0xD] ^= PC32dn(0x60, r); \
+		a[0xE] ^= PC32up(0x70, r); \
+		a[0xF] ^= PC32dn(0x70, r); \
+		RSTT(0x0, 0x1, a, 0x0, 0x2, 0x4, 0x6, 0x9, 0xB, 0xD, 0xF); \
+		RSTT(0x2, 0x3, a, 0x2, 0x4, 0x6, 0x8, 0xB, 0xD, 0xF, 0x1); \
+		RSTT(0x4, 0x5, a, 0x4, 0x6, 0x8, 0xA, 0xD, 0xF, 0x1, 0x3); \
+		RSTT(0x6, 0x7, a, 0x6, 0x8, 0xA, 0xC, 0xF, 0x1, 0x3, 0x5); \
+		RSTT(0x8, 0x9, a, 0x8, 0xA, 0xC, 0xE, 0x1, 0x3, 0x5, 0x7); \
+		RSTT(0xA, 0xB, a, 0xA, 0xC, 0xE, 0x0, 0x3, 0x5, 0x7, 0x9); \
+		RSTT(0xC, 0xD, a, 0xC, 0xE, 0x0, 0x2, 0x5, 0x7, 0x9, 0xB); \
+		RSTT(0xE, 0xF, a, 0xE, 0x0, 0x2, 0x4, 0x7, 0x9, 0xB, 0xD); \
+		memcpy(a, t, sizeof t); \
+	} while (0)
+
+#define ROUND_SMALL_Q(a, r)   do { \
+		sph_u32 t[16]; \
+		a[0x0] ^= QC32up(0x00, r); \
+		a[0x1] ^= QC32dn(0x00, r); \
+		a[0x2] ^= QC32up(0x10, r); \
+		a[0x3] ^= QC32dn(0x10, r); \
+		a[0x4] ^= QC32up(0x20, r); \
+		a[0x5] ^= QC32dn(0x20, r); \
+		a[0x6] ^= QC32up(0x30, r); \
+		a[0x7] ^= QC32dn(0x30, r); \
+		a[0x8] ^= QC32up(0x40, r); \
+		a[0x9] ^= QC32dn(0x40, r); \
+		a[0xA] ^= QC32up(0x50, r); \
+		a[0xB] ^= QC32dn(0x50, r); \
+		a[0xC] ^= QC32up(0x60, r); \
+		a[0xD] ^= QC32dn(0x60, r); \
+		a[0xE] ^= QC32up(0x70, r); \
+		a[0xF] ^= QC32dn(0x70, r); \
+		RSTT(0x0, 0x1, a, 0x2, 0x6, 0xA, 0xE, 0x1, 0x5, 0x9, 0xD); \
+		RSTT(0x2, 0x3, a, 0x4, 0x8, 0xC, 0x0, 0x3, 0x7, 0xB, 0xF); \
+		RSTT(0x4, 0x5, a, 0x6, 0xA, 0xE, 0x2, 0x5, 0x9, 0xD, 0x1); \
+		RSTT(0x6, 0x7, a, 0x8, 0xC, 0x0, 0x4, 0x7, 0xB, 0xF, 0x3); \
+		RSTT(0x8, 0x9, a, 0xA, 0xE, 0x2, 0x6, 0x9, 0xD, 0x1, 0x5); \
+		RSTT(0xA, 0xB, a, 0xC, 0x0, 0x4, 0x8, 0xB, 0xF, 0x3, 0x7); \
+		RSTT(0xC, 0xD, a, 0xE, 0x2, 0x6, 0xA, 0xD, 0x1, 0x5, 0x9); \
+		RSTT(0xE, 0xF, a, 0x0, 0x4, 0x8, 0xC, 0xF, 0x3, 0x7, 0xB); \
+		memcpy(a, t, sizeof t); \
+	} while (0)
+
+#define PERM_SMALL_P(a)   do { \
+		int r; \
+		for (r = 0; r < 10; r ++) \
+			ROUND_SMALL_P(a, r); \
+	} while (0)
+
+#define PERM_SMALL_Q(a)   do { \
+		int r; \
+		for (r = 0; r < 10; r ++) \
+			ROUND_SMALL_Q(a, r); \
+	} while (0)
+
+
+#define COMPRESS_SMALL   do { \
+		sph_u32 g[16], m[16]; \
+		size_t u; \
+		for (u = 0; u < 16; u ++) { \
+			m[u] = dec32e_aligned(buf + (u << 2)); \
+			g[u] = m[u] ^ H[u]; \
+		} \
+		PERM_SMALL_P(g); \
+		PERM_SMALL_Q(m); \
+		for (u = 0; u < 16; u ++) \
+			H[u] ^= g[u] ^ m[u]; \
+	} while (0)
+
+#define FINAL_SMALL   do { \
+		sph_u32 x[16]; \
+		size_t u; \
+		memcpy(x, H, sizeof x); \
+		PERM_SMALL_P(x); \
+		for (u = 0; u < 16; u ++) \
+			H[u] ^= x[u]; \
+	} while (0)
+
+#define DECL_STATE_BIG \
+	sph_u32 H[32] = {0};
+
+#define READ_STATE_BIG(sc)   do { \
+		memcpy(H, (sc)->state.narrow, sizeof H); \
+	} while (0)
+
+#define WRITE_STATE_BIG(sc)   do { \
+		memcpy((sc)->state.narrow, H, sizeof H); \
+	} while (0)
+
+
+#define RBTT(d0, d1, a, b0, b1, b2, b3, b4, b5, b6, b7)   do { \
+		sph_u32 fu2 = T0up[B32_2(a[b2])]; \
+		sph_u32 fd2 = T0dn[B32_2(a[b2])]; \
+		sph_u32 fu3 = T1up[B32_3(a[b3])]; \
+		sph_u32 fd3 = T1dn[B32_3(a[b3])]; \
+		sph_u32 fu6 = T0up[B32_2(a[b6])]; \
+		sph_u32 fd6 = T0dn[B32_2(a[b6])]; \
+		sph_u32 fu7 = T1up[B32_3(a[b7])]; \
+		sph_u32 fd7 = T1dn[B32_3(a[b7])]; \
+		t[d0] = T0up[B32_0(a[b0])] \
+			^ T1up[B32_1(a[b1])] \
+			^ R32u(fu2, fd2) \
+			^ R32u(fu3, fd3) \
+			^ T0dn[B32_0(a[b4])] \
+			^ T1dn[B32_1(a[b5])] \
+			^ R32d(fu6, fd6) \
+			^ R32d(fu7, fd7); \
+		t[d1] = T0dn[B32_0(a[b0])] \
+			^ T1dn[B32_1(a[b1])] \
+			^ R32d(fu2, fd2) \
+			^ R32d(fu3, fd3) \
+			^ T0up[B32_0(a[b4])] \
+			^ T1up[B32_1(a[b5])] \
+			^ R32u(fu6, fd6) \
+			^ R32u(fu7, fd7); \
+	} while (0)
+
+
+#define ROUND_BIG_P(a, r)   do { \
+		sph_u32 t[32]; \
+		size_t u; \
+		a[0x00] ^= PC32up(0x00, r); \
+		a[0x01] ^= PC32dn(0x00, r); \
+		a[0x02] ^= PC32up(0x10, r); \
+		a[0x03] ^= PC32dn(0x10, r); \
+		a[0x04] ^= PC32up(0x20, r); \
+		a[0x05] ^= PC32dn(0x20, r); \
+		a[0x06] ^= PC32up(0x30, r); \
+		a[0x07] ^= PC32dn(0x30, r); \
+		a[0x08] ^= PC32up(0x40, r); \
+		a[0x09] ^= PC32dn(0x40, r); \
+		a[0x0A] ^= PC32up(0x50, r); \
+		a[0x0B] ^= PC32dn(0x50, r); \
+		a[0x0C] ^= PC32up(0x60, r); \
+		a[0x0D] ^= PC32dn(0x60, r); \
+		a[0x0E] ^= PC32up(0x70, r); \
+		a[0x0F] ^= PC32dn(0x70, r); \
+		a[0x10] ^= PC32up(0x80, r); \
+		a[0x11] ^= PC32dn(0x80, r); \
+		a[0x12] ^= PC32up(0x90, r); \
+		a[0x13] ^= PC32dn(0x90, r); \
+		a[0x14] ^= PC32up(0xA0, r); \
+		a[0x15] ^= PC32dn(0xA0, r); \
+		a[0x16] ^= PC32up(0xB0, r); \
+		a[0x17] ^= PC32dn(0xB0, r); \
+		a[0x18] ^= PC32up(0xC0, r); \
+		a[0x19] ^= PC32dn(0xC0, r); \
+		a[0x1A] ^= PC32up(0xD0, r); \
+		a[0x1B] ^= PC32dn(0xD0, r); \
+		a[0x1C] ^= PC32up(0xE0, r); \
+		a[0x1D] ^= PC32dn(0xE0, r); \
+		a[0x1E] ^= PC32up(0xF0, r); \
+		a[0x1F] ^= PC32dn(0xF0, r); \
+		for (u = 0; u < 32; u += 8) { \
+			RBTT(u + 0x00, (u + 0x01) & 0x1F, a, \
+				u + 0x00, (u + 0x02) & 0x1F, \
+				(u + 0x04) & 0x1F, (u + 0x06) & 0x1F, \
+				(u + 0x09) & 0x1F, (u + 0x0B) & 0x1F, \
+				(u + 0x0D) & 0x1F, (u + 0x17) & 0x1F); \
+			RBTT(u + 0x02, (u + 0x03) & 0x1F, a, \
+				u + 0x02, (u + 0x04) & 0x1F, \
+				(u + 0x06) & 0x1F, (u + 0x08) & 0x1F, \
+				(u + 0x0B) & 0x1F, (u + 0x0D) & 0x1F, \
+				(u + 0x0F) & 0x1F, (u + 0x19) & 0x1F); \
+			RBTT(u + 0x04, (u + 0x05) & 0x1F, a, \
+				u + 0x04, (u + 0x06) & 0x1F, \
+				(u + 0x08) & 0x1F, (u + 0x0A) & 0x1F, \
+				(u + 0x0D) & 0x1F, (u + 0x0F) & 0x1F, \
+				(u + 0x11) & 0x1F, (u + 0x1B) & 0x1F); \
+			RBTT(u + 0x06, (u + 0x07) & 0x1F, a, \
+				u + 0x06, (u + 0x08) & 0x1F, \
+				(u + 0x0A) & 0x1F, (u + 0x0C) & 0x1F, \
+				(u + 0x0F) & 0x1F, (u + 0x11) & 0x1F, \
+				(u + 0x13) & 0x1F, (u + 0x1D) & 0x1F); \
+		} \
+		memcpy(a, t, sizeof t); \
+	} while (0)
+
+#define ROUND_BIG_Q(a, r)   do { \
+		sph_u32 t[32]; \
+		size_t u; \
+		a[0x00] ^= QC32up(0x00, r); \
+		a[0x01] ^= QC32dn(0x00, r); \
+		a[0x02] ^= QC32up(0x10, r); \
+		a[0x03] ^= QC32dn(0x10, r); \
+		a[0x04] ^= QC32up(0x20, r); \
+		a[0x05] ^= QC32dn(0x20, r); \
+		a[0x06] ^= QC32up(0x30, r); \
+		a[0x07] ^= QC32dn(0x30, r); \
+		a[0x08] ^= QC32up(0x40, r); \
+		a[0x09] ^= QC32dn(0x40, r); \
+		a[0x0A] ^= QC32up(0x50, r); \
+		a[0x0B] ^= QC32dn(0x50, r); \
+		a[0x0C] ^= QC32up(0x60, r); \
+		a[0x0D] ^= QC32dn(0x60, r); \
+		a[0x0E] ^= QC32up(0x70, r); \
+		a[0x0F] ^= QC32dn(0x70, r); \
+		a[0x10] ^= QC32up(0x80, r); \
+		a[0x11] ^= QC32dn(0x80, r); \
+		a[0x12] ^= QC32up(0x90, r); \
+		a[0x13] ^= QC32dn(0x90, r); \
+		a[0x14] ^= QC32up(0xA0, r); \
+		a[0x15] ^= QC32dn(0xA0, r); \
+		a[0x16] ^= QC32up(0xB0, r); \
+		a[0x17] ^= QC32dn(0xB0, r); \
+		a[0x18] ^= QC32up(0xC0, r); \
+		a[0x19] ^= QC32dn(0xC0, r); \
+		a[0x1A] ^= QC32up(0xD0, r); \
+		a[0x1B] ^= QC32dn(0xD0, r); \
+		a[0x1C] ^= QC32up(0xE0, r); \
+		a[0x1D] ^= QC32dn(0xE0, r); \
+		a[0x1E] ^= QC32up(0xF0, r); \
+		a[0x1F] ^= QC32dn(0xF0, r); \
+		for (u = 0; u < 32; u += 8) { \
+			RBTT(u + 0x00, (u + 0x01) & 0x1F, a, \
+				(u + 0x02) & 0x1F, (u + 0x06) & 0x1F, \
+				(u + 0x0A) & 0x1F, (u + 0x16) & 0x1F, \
+				(u + 0x01) & 0x1F, (u + 0x05) & 0x1F, \
+				(u + 0x09) & 0x1F, (u + 0x0D) & 0x1F); \
+			RBTT(u + 0x02, (u + 0x03) & 0x1F, a, \
+				(u + 0x04) & 0x1F, (u + 0x08) & 0x1F, \
+				(u + 0x0C) & 0x1F, (u + 0x18) & 0x1F, \
+				(u + 0x03) & 0x1F, (u + 0x07) & 0x1F, \
+				(u + 0x0B) & 0x1F, (u + 0x0F) & 0x1F); \
+			RBTT(u + 0x04, (u + 0x05) & 0x1F, a, \
+				(u + 0x06) & 0x1F, (u + 0x0A) & 0x1F, \
+				(u + 0x0E) & 0x1F, (u + 0x1A) & 0x1F, \
+				(u + 0x05) & 0x1F, (u + 0x09) & 0x1F, \
+				(u + 0x0D) & 0x1F, (u + 0x11) & 0x1F); \
+			RBTT(u + 0x06, (u + 0x07) & 0x1F, a, \
+				(u + 0x08) & 0x1F, (u + 0x0C) & 0x1F, \
+				(u + 0x10) & 0x1F, (u + 0x1C) & 0x1F, \
+				(u + 0x07) & 0x1F, (u + 0x0B) & 0x1F, \
+				(u + 0x0F) & 0x1F, (u + 0x13) & 0x1F); \
+		} \
+		memcpy(a, t, sizeof t); \
+	} while (0)
+
+
+#define PERM_BIG_P(a)   do { \
+		int r; \
+		for (r = 0; r < 14; r ++) \
+			ROUND_BIG_P(a, r); \
+	} while (0)
+
+#define PERM_BIG_Q(a)   do { \
+		int r; \
+		for (r = 0; r < 14; r ++) \
+			ROUND_BIG_Q(a, r); \
+	} while (0)
+
+
+#define COMPRESS_BIG   do { \
+		sph_u32 g[32], m[32]; \
+		size_t uu; \
+		for (uu = 0; uu < 32; uu ++) { \
+			m[uu] = dec32e_aligned(buf + (uu << 2)); \
+			g[uu] = m[uu] ^ H[uu]; \
+		} \
+		PERM_BIG_P(g); \
+		PERM_BIG_Q(m); \
+		for (uu = 0; uu < 32; uu ++) \
+			H[uu] ^= g[uu] ^ m[uu]; \
+	} while (0)
+
+#define FINAL_BIG   do { \
+		sph_u32 x[32]; \
+		size_t uu; \
+		memcpy(x, H, sizeof x); \
+		PERM_BIG_P(x); \
+		for (uu = 0; uu < 32; uu ++) \
+			H[uu] ^= x[uu]; \
+	} while (0)
+
+
+static void
+groestl_big_init(sph_groestl_big_context *sc, unsigned out_size)
+{
+	size_t u = 0;
+
+	sc->ptr = 0;
+	for (u = 0; u < 31; u ++)
+		sc->state.narrow[u] = 0;
+	sc->state.narrow[31] = ((sph_u32)(out_size & 0xFF) << 24)
+		| ((sph_u32)(out_size & 0xFF00) << 8);
+	sc->count = 0;
+}
+
+static void
+groestl_big_core(sph_groestl_big_context *sc, const void *data, size_t len)
+{
+  if (len == 0) {
+    return;
+  }
+
+	unsigned char *buf = NULL;
+	size_t ptr = 0;
+	DECL_STATE_BIG
+
+	buf = sc->buf;
+	ptr = sc->ptr;
+	if (len < (sizeof sc->buf) - ptr) {
+		memcpy(buf + ptr, data, len);
+		ptr += len;
+		sc->ptr = ptr;
+		return;
+	}
+
+	READ_STATE_BIG(sc);
+	while (len > 0) {
+		size_t clen = 0;
+
+		clen = (sizeof sc->buf) - ptr;
+		if (clen > len)
+			clen = len;
+		memcpy(buf + ptr, data, clen);
+		ptr += clen;
+		data = (const unsigned char *)data + clen;
+		len -= clen;
+		if (ptr == sizeof sc->buf) {
+			COMPRESS_BIG;
+			sc->count ++;
+			ptr = 0;
+		}
+	}
+	WRITE_STATE_BIG(sc);
+	sc->ptr = ptr;
+}
+
+static void
+groestl_big_close(sph_groestl_big_context *sc,
+	unsigned ub, unsigned n, void *dst, size_t out_len)
+{
+	unsigned char pad[136] = {0};
+	size_t ptr = 0, pad_len = 0, u2 = 0;
+	sph_u64 count = 0;
+	unsigned z = 0;
+	DECL_STATE_BIG
+
+	ptr = sc->ptr;
+	z = 0x80 >> n;
+	pad[0] = ((ub & -z) | z) & 0xFF;
+	if (ptr < 120) {
+		pad_len = 128 - ptr;
+		count = SPH_T64(sc->count + 1);
+	} else {
+		pad_len = 256 - ptr;
+		count = SPH_T64(sc->count + 2);
+	}
+	memzero(pad + 1, pad_len - 9);
+	sph_enc64be(pad + pad_len - 8, count);
+	groestl_big_core(sc, pad, pad_len);
+	READ_STATE_BIG(sc);
+	FINAL_BIG;
+	for (u2 = 0; u2 < 16; u2 ++)
+		enc32e(pad + (u2 << 2), H[u2 + 16]);
+	memcpy(dst, pad + 64 - out_len, out_len);
+	groestl_big_init(sc, (unsigned)out_len << 3);
+}
+
+void
+groestl512_Init(void *cc)
+{
+	groestl_big_init((sph_groestl_big_context *)cc, 512);
+}
+
+void
+groestl512_Update(void *cc, const void *data, size_t len)
+{
+	groestl_big_core((sph_groestl_big_context *)cc, data, len);
+}
+
+void
+groestl512_Final(void *cc, void *dst)
+{
+	groestl_big_close((sph_groestl_big_context *)cc, 0, 0, dst, 64);
+}
+
+void
+groestl512_DoubleTrunc(void *cc, void *dst)
+{
+	char buf[64] = {0};
+
+	groestl512_Final(cc, buf);
+	groestl512_Update(cc, buf, sizeof(buf));
+	groestl512_Final(cc, buf);
+	memcpy(dst, buf, 32);
+}

+ 95 - 0
crypto/groestl.h

@@ -0,0 +1,95 @@
+/* Groestl hash from https://github.com/Groestlcoin/vanitygen
+ * Trezor adaptation by Yura Pakhuchiy <pakhuchiy@gmail.com>. */
+/**
+ * Groestl interface. This code implements Groestl with the recommended
+ * parameters for SHA-3, with outputs of 224, 256, 384 and 512 bits.
+ *
+ * ==========================(LICENSE BEGIN)============================
+ *
+ * Copyright (c) 2007-2010  Projet RNRT SAPHIR
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ===========================(LICENSE END)=============================
+ *
+ * @file     sph_groestl.h
+ * @author   Thomas Pornin <thomas.pornin@cryptolog.com>
+ */
+
+#ifndef GROESTL_H__
+#define GROESTL_H__
+
+#include <stddef.h>
+
+/**
+ * This structure is a context for Groestl-384 and Groestl-512 computations:
+ * it contains the intermediate values and some data from the last
+ * entered block. Once a Groestl computation has been performed, the
+ * context can be reused for another computation.
+ *
+ * The contents of this structure are private. A running Groestl
+ * computation can be cloned by copying the context (e.g. with a simple
+ * <code>memcpy()</code>).
+ */
+typedef struct {
+	unsigned char buf[128];    /* first field, for alignment */
+	size_t ptr;
+	union {
+		uint64_t wide[16];
+		uint32_t narrow[32];
+	} state;
+	uint64_t count;
+} sph_groestl_big_context;
+
+typedef sph_groestl_big_context GROESTL512_CTX;
+
+/**
+ * Initialize a Groestl-512 context. This process performs no memory allocation.
+ *
+ * @param cc   the Groestl-512 context (pointer to a
+ *             <code>GROESTL512_CTX</code>)
+ */
+void groestl512_Init(void *cc);
+
+/**
+ * Process some data bytes. It is acceptable that <code>len</code> is zero
+ * (in which case this function does nothing).
+ *
+ * @param cc     the Groestl-512 context
+ * @param data   the input data
+ * @param len    the input data length (in bytes)
+ */
+void groestl512_Update(void *cc, const void *data, size_t len);
+
+/**
+ * Terminate the current Groestl-512 computation and output the result into
+ * the provided buffer. The destination buffer must be wide enough to
+ * accomodate the result (64 bytes). The context is automatically
+ * reinitialized.
+ *
+ * @param cc    the Groestl-512 context
+ * @param dst   the destination buffer
+ */
+void groestl512_Final(void *cc, void *dst);
+
+/* Calculate double Groestl-512 hash and truncate it to 256-bits. */
+void groestl512_DoubleTrunc(void *cc, void *dst);
+
+#endif

+ 509 - 0
crypto/groestl_internal.h

@@ -0,0 +1,509 @@
+/* Groestl hash from https://github.com/Groestlcoin/vanitygen
+ * Trezor adaptation by Yura Pakhuchiy <pakhuchiy@gmail.com>. */
+/**
+ * Basic type definitions.
+ *
+ * This header file defines the generic integer types that will be used
+ * for the implementation of hash functions; it also contains helper
+ * functions which encode and decode multi-byte integer values, using
+ * either little-endian or big-endian conventions.
+ *
+ * This file contains a compile-time test on the size of a byte
+ * (the <code>unsigned char</code> C type). If bytes are not octets,
+ * i.e. if they do not have a size of exactly 8 bits, then compilation
+ * is aborted. Architectures where bytes are not octets are relatively
+ * rare, even in the embedded devices market. We forbid non-octet bytes
+ * because there is no clear convention on how octet streams are encoded
+ * on such systems.
+ *
+ * ==========================(LICENSE BEGIN)============================
+ *
+ * Copyright (c) 2007-2010  Projet RNRT SAPHIR
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ===========================(LICENSE END)=============================
+ *
+ * @file     sph_types.h
+ * @author   Thomas Pornin <thomas.pornin@cryptolog.com>
+ */
+
+#ifndef GROESTL_INTERNAL_H__
+#define GROESTL_INTERNAL_H__
+
+#include <limits.h>
+
+/*
+ * All our I/O functions are defined over octet streams. We do not know
+ * how to handle input data if bytes are not octets.
+ */
+#if CHAR_BIT != 8
+#error This code requires 8-bit bytes
+#endif
+
+#if defined __STDC__ && __STDC_VERSION__ >= 199901L
+
+#include <stdint.h>
+
+typedef uint32_t sph_u32;
+typedef int32_t sph_s32;
+typedef uint64_t sph_u64;
+typedef int64_t sph_s64;
+
+#define SPH_C32(x)    ((sph_u32)(x))
+#define SPH_C64(x)    ((sph_u64)(x))
+
+#else
+#error We need at least C99 compiler
+#endif
+
+#define SPH_T32(x)    ((x) & SPH_C32(0xFFFFFFFF))
+#define SPH_ROTL32(x, n)   SPH_T32(((x) << (n)) | ((x) >> (32 - (n))))
+#define SPH_ROTR32(x, n)   SPH_ROTL32(x, (32 - (n)))
+
+#define SPH_T64(x)    ((x) & SPH_C64(0xFFFFFFFFFFFFFFFF))
+#define SPH_ROTL64(x, n)   SPH_T64(((x) << (n)) | ((x) >> (64 - (n))))
+#define SPH_ROTR64(x, n)   SPH_ROTL64(x, (64 - (n)))
+
+/*
+ * 32-bit x86, aka "i386 compatible".
+ */
+#if defined __i386__ || defined _M_IX86
+
+#define SPH_DETECT_LITTLE_ENDIAN     1
+#define SPH_DETECT_BIG_ENDIAN        0
+
+/*
+ * 64-bit x86, hereafter known as "amd64".
+ */
+#elif defined __x86_64 || defined _M_X64
+
+#define SPH_DETECT_LITTLE_ENDIAN     1
+#define SPH_DETECT_BIG_ENDIAN        0
+
+/*
+ * ARM, little-endian.
+ */
+#elif defined __arm__ && __ARMEL__
+
+#define SPH_DETECT_LITTLE_ENDIAN     1
+#define SPH_DETECT_BIG_ENDIAN        0
+
+/*
+ * ARM64, little-endian.
+ */
+#elif defined __aarch64__
+
+#define SPH_DETECT_LITTLE_ENDIAN     1
+#define SPH_DETECT_BIG_ENDIAN        0
+
+#endif
+
+
+#if defined SPH_DETECT_LITTLE_ENDIAN && !defined SPH_LITTLE_ENDIAN
+#define SPH_LITTLE_ENDIAN     SPH_DETECT_LITTLE_ENDIAN
+#endif
+#if defined SPH_DETECT_BIG_ENDIAN && !defined SPH_BIG_ENDIAN
+#define SPH_BIG_ENDIAN        SPH_DETECT_BIG_ENDIAN
+#endif
+
+static inline sph_u32
+sph_bswap32(sph_u32 x)
+{
+	x = SPH_T32((x << 16) | (x >> 16));
+	x = ((x & SPH_C32(0xFF00FF00)) >> 8)
+		| ((x & SPH_C32(0x00FF00FF)) << 8);
+	return x;
+}
+
+/**
+ * Byte-swap a 64-bit value.
+ *
+ * @param x   the input value
+ * @return  the byte-swapped value
+ */
+static inline sph_u64
+sph_bswap64(sph_u64 x)
+{
+	x = SPH_T64((x << 32) | (x >> 32));
+	x = ((x & SPH_C64(0xFFFF0000FFFF0000)) >> 16)
+		| ((x & SPH_C64(0x0000FFFF0000FFFF)) << 16);
+	x = ((x & SPH_C64(0xFF00FF00FF00FF00)) >> 8)
+		| ((x & SPH_C64(0x00FF00FF00FF00FF)) << 8);
+	return x;
+}
+
+static inline void
+sph_enc16be(void *dst, unsigned val)
+{
+	((unsigned char *)dst)[0] = (val >> 8);
+	((unsigned char *)dst)[1] = val;
+}
+
+static inline unsigned
+sph_dec16be(const void *src)
+{
+	return ((unsigned)(((const unsigned char *)src)[0]) << 8)
+		| (unsigned)(((const unsigned char *)src)[1]);
+}
+
+static inline void
+sph_enc16le(void *dst, unsigned val)
+{
+	((unsigned char *)dst)[0] = val;
+	((unsigned char *)dst)[1] = val >> 8;
+}
+
+static inline unsigned
+sph_dec16le(const void *src)
+{
+	return (unsigned)(((const unsigned char *)src)[0])
+		| ((unsigned)(((const unsigned char *)src)[1]) << 8);
+}
+
+/**
+ * Encode a 32-bit value into the provided buffer (big endian convention).
+ *
+ * @param dst   the destination buffer
+ * @param val   the 32-bit value to encode
+ */
+static inline void
+sph_enc32be(void *dst, sph_u32 val)
+{
+	((unsigned char *)dst)[0] = (val >> 24);
+	((unsigned char *)dst)[1] = (val >> 16);
+	((unsigned char *)dst)[2] = (val >> 8);
+	((unsigned char *)dst)[3] = val;
+}
+
+/**
+ * Encode a 32-bit value into the provided buffer (big endian convention).
+ * The destination buffer must be properly aligned.
+ *
+ * @param dst   the destination buffer (32-bit aligned)
+ * @param val   the value to encode
+ */
+static inline void
+sph_enc32be_aligned(void *dst, sph_u32 val)
+{
+#if SPH_LITTLE_ENDIAN
+	*(sph_u32 *)dst = sph_bswap32(val);
+#elif SPH_BIG_ENDIAN
+	*(sph_u32 *)dst = val;
+#else
+	((unsigned char *)dst)[0] = (val >> 24);
+	((unsigned char *)dst)[1] = (val >> 16);
+	((unsigned char *)dst)[2] = (val >> 8);
+	((unsigned char *)dst)[3] = val;
+#endif
+}
+
+/**
+ * Decode a 32-bit value from the provided buffer (big endian convention).
+ *
+ * @param src   the source buffer
+ * @return  the decoded value
+ */
+static inline sph_u32
+sph_dec32be(const void *src)
+{
+	return ((sph_u32)(((const unsigned char *)src)[0]) << 24)
+		| ((sph_u32)(((const unsigned char *)src)[1]) << 16)
+		| ((sph_u32)(((const unsigned char *)src)[2]) << 8)
+		| (sph_u32)(((const unsigned char *)src)[3]);
+}
+
+/**
+ * Decode a 32-bit value from the provided buffer (big endian convention).
+ * The source buffer must be properly aligned.
+ *
+ * @param src   the source buffer (32-bit aligned)
+ * @return  the decoded value
+ */
+static inline sph_u32
+sph_dec32be_aligned(const void *src)
+{
+#if SPH_LITTLE_ENDIAN
+	return sph_bswap32(*(const sph_u32 *)src);
+#elif SPH_BIG_ENDIAN
+	return *(const sph_u32 *)src;
+#else
+	return ((sph_u32)(((const unsigned char *)src)[0]) << 24)
+		| ((sph_u32)(((const unsigned char *)src)[1]) << 16)
+		| ((sph_u32)(((const unsigned char *)src)[2]) << 8)
+		| (sph_u32)(((const unsigned char *)src)[3]);
+#endif
+}
+
+/**
+ * Encode a 32-bit value into the provided buffer (little endian convention).
+ *
+ * @param dst   the destination buffer
+ * @param val   the 32-bit value to encode
+ */
+static inline void
+sph_enc32le(void *dst, sph_u32 val)
+{
+	((unsigned char *)dst)[0] = val;
+	((unsigned char *)dst)[1] = (val >> 8);
+	((unsigned char *)dst)[2] = (val >> 16);
+	((unsigned char *)dst)[3] = (val >> 24);
+}
+
+/**
+ * Encode a 32-bit value into the provided buffer (little endian convention).
+ * The destination buffer must be properly aligned.
+ *
+ * @param dst   the destination buffer (32-bit aligned)
+ * @param val   the value to encode
+ */
+static inline void
+sph_enc32le_aligned(void *dst, sph_u32 val)
+{
+#if SPH_LITTLE_ENDIAN
+	*(sph_u32 *)dst = val;
+#elif SPH_BIG_ENDIAN
+	*(sph_u32 *)dst = sph_bswap32(val);
+#else
+	((unsigned char *)dst)[0] = val;
+	((unsigned char *)dst)[1] = (val >> 8);
+	((unsigned char *)dst)[2] = (val >> 16);
+	((unsigned char *)dst)[3] = (val >> 24);
+#endif
+}
+
+/**
+ * Decode a 32-bit value from the provided buffer (little endian convention).
+ *
+ * @param src   the source buffer
+ * @return  the decoded value
+ */
+static inline sph_u32
+sph_dec32le(const void *src)
+{
+	return (sph_u32)(((const unsigned char *)src)[0])
+		| ((sph_u32)(((const unsigned char *)src)[1]) << 8)
+		| ((sph_u32)(((const unsigned char *)src)[2]) << 16)
+		| ((sph_u32)(((const unsigned char *)src)[3]) << 24);
+}
+
+/**
+ * Decode a 32-bit value from the provided buffer (little endian convention).
+ * The source buffer must be properly aligned.
+ *
+ * @param src   the source buffer (32-bit aligned)
+ * @return  the decoded value
+ */
+static inline sph_u32
+sph_dec32le_aligned(const void *src)
+{
+#if SPH_LITTLE_ENDIAN
+	return *(const sph_u32 *)src;
+#elif SPH_BIG_ENDIAN
+	return sph_bswap32(*(const sph_u32 *)src);
+#else
+	return (sph_u32)(((const unsigned char *)src)[0])
+		| ((sph_u32)(((const unsigned char *)src)[1]) << 8)
+		| ((sph_u32)(((const unsigned char *)src)[2]) << 16)
+		| ((sph_u32)(((const unsigned char *)src)[3]) << 24);
+#endif
+}
+
+/**
+ * Encode a 64-bit value into the provided buffer (big endian convention).
+ *
+ * @param dst   the destination buffer
+ * @param val   the 64-bit value to encode
+ */
+static inline void
+sph_enc64be(void *dst, sph_u64 val)
+{
+	((unsigned char *)dst)[0] = (val >> 56);
+	((unsigned char *)dst)[1] = (val >> 48);
+	((unsigned char *)dst)[2] = (val >> 40);
+	((unsigned char *)dst)[3] = (val >> 32);
+	((unsigned char *)dst)[4] = (val >> 24);
+	((unsigned char *)dst)[5] = (val >> 16);
+	((unsigned char *)dst)[6] = (val >> 8);
+	((unsigned char *)dst)[7] = val;
+}
+
+/**
+ * Encode a 64-bit value into the provided buffer (big endian convention).
+ * The destination buffer must be properly aligned.
+ *
+ * @param dst   the destination buffer (64-bit aligned)
+ * @param val   the value to encode
+ */
+static inline void
+sph_enc64be_aligned(void *dst, sph_u64 val)
+{
+#if SPH_LITTLE_ENDIAN
+	*(sph_u64 *)dst = sph_bswap64(val);
+#elif SPH_BIG_ENDIAN
+	*(sph_u64 *)dst = val;
+#else
+	((unsigned char *)dst)[0] = (val >> 56);
+	((unsigned char *)dst)[1] = (val >> 48);
+	((unsigned char *)dst)[2] = (val >> 40);
+	((unsigned char *)dst)[3] = (val >> 32);
+	((unsigned char *)dst)[4] = (val >> 24);
+	((unsigned char *)dst)[5] = (val >> 16);
+	((unsigned char *)dst)[6] = (val >> 8);
+	((unsigned char *)dst)[7] = val;
+#endif
+}
+
+/**
+ * Decode a 64-bit value from the provided buffer (big endian convention).
+ *
+ * @param src   the source buffer
+ * @return  the decoded value
+ */
+static inline sph_u64
+sph_dec64be(const void *src)
+{
+	return ((sph_u64)(((const unsigned char *)src)[0]) << 56)
+		| ((sph_u64)(((const unsigned char *)src)[1]) << 48)
+		| ((sph_u64)(((const unsigned char *)src)[2]) << 40)
+		| ((sph_u64)(((const unsigned char *)src)[3]) << 32)
+		| ((sph_u64)(((const unsigned char *)src)[4]) << 24)
+		| ((sph_u64)(((const unsigned char *)src)[5]) << 16)
+		| ((sph_u64)(((const unsigned char *)src)[6]) << 8)
+		| (sph_u64)(((const unsigned char *)src)[7]);
+}
+
+/**
+ * Decode a 64-bit value from the provided buffer (big endian convention).
+ * The source buffer must be properly aligned.
+ *
+ * @param src   the source buffer (64-bit aligned)
+ * @return  the decoded value
+ */
+static inline sph_u64
+sph_dec64be_aligned(const void *src)
+{
+#if SPH_LITTLE_ENDIAN
+	return sph_bswap64(*(const sph_u64 *)src);
+#elif SPH_BIG_ENDIAN
+	return *(const sph_u64 *)src;
+#else
+	return ((sph_u64)(((const unsigned char *)src)[0]) << 56)
+		| ((sph_u64)(((const unsigned char *)src)[1]) << 48)
+		| ((sph_u64)(((const unsigned char *)src)[2]) << 40)
+		| ((sph_u64)(((const unsigned char *)src)[3]) << 32)
+		| ((sph_u64)(((const unsigned char *)src)[4]) << 24)
+		| ((sph_u64)(((const unsigned char *)src)[5]) << 16)
+		| ((sph_u64)(((const unsigned char *)src)[6]) << 8)
+		| (sph_u64)(((const unsigned char *)src)[7]);
+#endif
+}
+
+/**
+ * Encode a 64-bit value into the provided buffer (little endian convention).
+ *
+ * @param dst   the destination buffer
+ * @param val   the 64-bit value to encode
+ */
+static inline void
+sph_enc64le(void *dst, sph_u64 val)
+{
+	((unsigned char *)dst)[0] = val;
+	((unsigned char *)dst)[1] = (val >> 8);
+	((unsigned char *)dst)[2] = (val >> 16);
+	((unsigned char *)dst)[3] = (val >> 24);
+	((unsigned char *)dst)[4] = (val >> 32);
+	((unsigned char *)dst)[5] = (val >> 40);
+	((unsigned char *)dst)[6] = (val >> 48);
+	((unsigned char *)dst)[7] = (val >> 56);
+}
+
+/**
+ * Encode a 64-bit value into the provided buffer (little endian convention).
+ * The destination buffer must be properly aligned.
+ *
+ * @param dst   the destination buffer (64-bit aligned)
+ * @param val   the value to encode
+ */
+static inline void
+sph_enc64le_aligned(void *dst, sph_u64 val)
+{
+#if SPH_LITTLE_ENDIAN
+	*(sph_u64 *)dst = val;
+#elif SPH_BIG_ENDIAN
+	*(sph_u64 *)dst = sph_bswap64(val);
+#else
+	((unsigned char *)dst)[0] = val;
+	((unsigned char *)dst)[1] = (val >> 8);
+	((unsigned char *)dst)[2] = (val >> 16);
+	((unsigned char *)dst)[3] = (val >> 24);
+	((unsigned char *)dst)[4] = (val >> 32);
+	((unsigned char *)dst)[5] = (val >> 40);
+	((unsigned char *)dst)[6] = (val >> 48);
+	((unsigned char *)dst)[7] = (val >> 56);
+#endif
+}
+
+/**
+ * Decode a 64-bit value from the provided buffer (little endian convention).
+ *
+ * @param src   the source buffer
+ * @return  the decoded value
+ */
+static inline sph_u64
+sph_dec64le(const void *src)
+{
+	return (sph_u64)(((const unsigned char *)src)[0])
+		| ((sph_u64)(((const unsigned char *)src)[1]) << 8)
+		| ((sph_u64)(((const unsigned char *)src)[2]) << 16)
+		| ((sph_u64)(((const unsigned char *)src)[3]) << 24)
+		| ((sph_u64)(((const unsigned char *)src)[4]) << 32)
+		| ((sph_u64)(((const unsigned char *)src)[5]) << 40)
+		| ((sph_u64)(((const unsigned char *)src)[6]) << 48)
+		| ((sph_u64)(((const unsigned char *)src)[7]) << 56);
+}
+
+/**
+ * Decode a 64-bit value from the provided buffer (little endian convention).
+ * The source buffer must be properly aligned.
+ *
+ * @param src   the source buffer (64-bit aligned)
+ * @return  the decoded value
+ */
+static inline sph_u64
+sph_dec64le_aligned(const void *src)
+{
+#if SPH_LITTLE_ENDIAN
+	return *(const sph_u64 *)src;
+#elif SPH_BIG_ENDIAN
+	return sph_bswap64(*(const sph_u64 *)src);
+#else
+	return (sph_u64)(((const unsigned char *)src)[0])
+		| ((sph_u64)(((const unsigned char *)src)[1]) << 8)
+		| ((sph_u64)(((const unsigned char *)src)[2]) << 16)
+		| ((sph_u64)(((const unsigned char *)src)[3]) << 24)
+		| ((sph_u64)(((const unsigned char *)src)[4]) << 32)
+		| ((sph_u64)(((const unsigned char *)src)[5]) << 40)
+		| ((sph_u64)(((const unsigned char *)src)[6]) << 48)
+		| ((sph_u64)(((const unsigned char *)src)[7]) << 56);
+#endif
+}
+
+#endif

+ 157 - 0
crypto/hasher.c

@@ -0,0 +1,157 @@
+/**
+ * Copyright (c) 2017 Saleem Rashid
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
+ * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "hasher.h"
+#include "ripemd160.h"
+
+const uint32_t sha256_initial_tapsighash_state[8] = {
+    0xf504a425UL, 0xd7f8783bUL, 0x1363868aUL, 0xe3e55658UL,
+    0x6eee945dUL, 0xbc7888ddUL, 0x02a6e2c3UL, 0x1873fe9fUL,
+};
+
+void hasher_InitParam(Hasher *hasher, HasherType type, const void *param,
+                      uint32_t param_size) {
+  hasher->type = type;
+  hasher->param = param;
+  hasher->param_size = param_size;
+
+  switch (hasher->type) {
+    case HASHER_SHA2:
+    case HASHER_SHA2D:
+    case HASHER_SHA2_RIPEMD:
+      sha256_Init(&hasher->ctx.sha2);
+      break;
+    case HASHER_SHA2_TAPSIGHASH:
+      sha256_Init_ex(&hasher->ctx.sha2, sha256_initial_tapsighash_state, 512);
+      break;
+    case HASHER_SHA3:
+#if USE_KECCAK
+    case HASHER_SHA3K:
+#endif
+      sha3_256_Init(&hasher->ctx.sha3);
+      break;
+    case HASHER_BLAKE:
+    case HASHER_BLAKED:
+    case HASHER_BLAKE_RIPEMD:
+      blake256_Init(&hasher->ctx.blake);
+      break;
+    case HASHER_GROESTLD_TRUNC:
+      groestl512_Init(&hasher->ctx.groestl);
+      break;
+    case HASHER_BLAKE2B:
+      blake2b_Init(&hasher->ctx.blake2b, 32);
+      break;
+    case HASHER_BLAKE2B_PERSONAL:
+      blake2b_InitPersonal(&hasher->ctx.blake2b, 32, hasher->param,
+                           hasher->param_size);
+      break;
+  }
+}
+
+void hasher_Init(Hasher *hasher, HasherType type) {
+  hasher_InitParam(hasher, type, NULL, 0);
+}
+
+void hasher_Reset(Hasher *hasher) {
+  hasher_InitParam(hasher, hasher->type, hasher->param, hasher->param_size);
+}
+
+void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length) {
+  switch (hasher->type) {
+    case HASHER_SHA2:
+    case HASHER_SHA2D:
+    case HASHER_SHA2_RIPEMD:
+    case HASHER_SHA2_TAPSIGHASH:
+      sha256_Update(&hasher->ctx.sha2, data, length);
+      break;
+    case HASHER_SHA3:
+#if USE_KECCAK
+    case HASHER_SHA3K:
+#endif
+      sha3_Update(&hasher->ctx.sha3, data, length);
+      break;
+    case HASHER_BLAKE:
+    case HASHER_BLAKED:
+    case HASHER_BLAKE_RIPEMD:
+      blake256_Update(&hasher->ctx.blake, data, length);
+      break;
+    case HASHER_GROESTLD_TRUNC:
+      groestl512_Update(&hasher->ctx.groestl, data, length);
+      break;
+    case HASHER_BLAKE2B:
+    case HASHER_BLAKE2B_PERSONAL:
+      blake2b_Update(&hasher->ctx.blake2b, data, length);
+      break;
+  }
+}
+
+void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]) {
+  switch (hasher->type) {
+    case HASHER_SHA2:
+    case HASHER_SHA2_TAPSIGHASH:
+      sha256_Final(&hasher->ctx.sha2, hash);
+      break;
+    case HASHER_SHA2D:
+      sha256_Final(&hasher->ctx.sha2, hash);
+      hasher_Raw(HASHER_SHA2, hash, HASHER_DIGEST_LENGTH, hash);
+      break;
+    case HASHER_SHA2_RIPEMD:
+      sha256_Final(&hasher->ctx.sha2, hash);
+      ripemd160(hash, HASHER_DIGEST_LENGTH, hash);
+      break;
+    case HASHER_SHA3:
+      sha3_Final(&hasher->ctx.sha3, hash);
+      break;
+#if USE_KECCAK
+    case HASHER_SHA3K:
+      keccak_Final(&hasher->ctx.sha3, hash);
+      break;
+#endif
+    case HASHER_BLAKE:
+      blake256_Final(&hasher->ctx.blake, hash);
+      break;
+    case HASHER_BLAKED:
+      blake256_Final(&hasher->ctx.blake, hash);
+      hasher_Raw(HASHER_BLAKE, hash, HASHER_DIGEST_LENGTH, hash);
+      break;
+    case HASHER_BLAKE_RIPEMD:
+      blake256_Final(&hasher->ctx.blake, hash);
+      ripemd160(hash, HASHER_DIGEST_LENGTH, hash);
+      break;
+    case HASHER_GROESTLD_TRUNC:
+      groestl512_DoubleTrunc(&hasher->ctx.groestl, hash);
+      break;
+    case HASHER_BLAKE2B:
+    case HASHER_BLAKE2B_PERSONAL:
+      blake2b_Final(&hasher->ctx.blake2b, hash, 32);
+      break;
+  }
+}
+
+void hasher_Raw(HasherType type, const uint8_t *data, size_t length,
+                uint8_t hash[HASHER_DIGEST_LENGTH]) {
+  Hasher hasher = {0};
+
+  hasher_Init(&hasher, type);
+  hasher_Update(&hasher, data, length);
+  hasher_Final(&hasher, hash);
+}

+ 83 - 0
crypto/hasher.h

@@ -0,0 +1,83 @@
+/**
+ * Copyright (c) 2017 Saleem Rashid
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
+ * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __HASHER_H__
+#define __HASHER_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "blake256.h"
+#include "blake2b.h"
+#include "groestl.h"
+#include "sha2.h"
+#include "sha3.h"
+
+#define HASHER_DIGEST_LENGTH 32
+
+typedef enum {
+  HASHER_SHA2,
+  HASHER_SHA2D,
+  HASHER_SHA2_RIPEMD,
+  HASHER_SHA2_TAPSIGHASH,
+
+  HASHER_SHA3,
+#if USE_KECCAK
+  HASHER_SHA3K,
+#endif
+
+  HASHER_BLAKE,
+  HASHER_BLAKED,
+  HASHER_BLAKE_RIPEMD,
+
+  HASHER_GROESTLD_TRUNC, /* Double Groestl512 hasher truncated to 256 bits */
+
+  HASHER_BLAKE2B,
+  HASHER_BLAKE2B_PERSONAL,
+} HasherType;
+
+typedef struct {
+  HasherType type;
+
+  union {
+    SHA256_CTX sha2;         // for HASHER_SHA2{,D}
+    SHA3_CTX sha3;           // for HASHER_SHA3{,K}
+    BLAKE256_CTX blake;      // for HASHER_BLAKE{,D}
+    GROESTL512_CTX groestl;  // for HASHER_GROESTLD_TRUNC
+    BLAKE2B_CTX blake2b;     // for HASHER_BLAKE2B{,_PERSONAL}
+  } ctx;
+
+  const void *param;
+  uint32_t param_size;
+} Hasher;
+
+void hasher_InitParam(Hasher *hasher, HasherType type, const void *param,
+                      uint32_t param_size);
+void hasher_Init(Hasher *hasher, HasherType type);
+void hasher_Reset(Hasher *hasher);
+void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length);
+void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]);
+
+void hasher_Raw(HasherType type, const uint8_t *data, size_t length,
+                uint8_t hash[HASHER_DIGEST_LENGTH]);
+
+#endif

+ 176 - 0
crypto/hmac.c

@@ -0,0 +1,176 @@
+/**
+ * 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 <string.h>
+
+#include "hmac.h"
+#include "memzero.h"
+#include "options.h"
+
+void hmac_sha256_Init(HMAC_SHA256_CTX *hctx, const uint8_t *key,
+                      const uint32_t keylen) {
+  static CONFIDENTIAL uint8_t i_key_pad[SHA256_BLOCK_LENGTH];
+  memzero(i_key_pad, SHA256_BLOCK_LENGTH);
+  if (keylen > SHA256_BLOCK_LENGTH) {
+    sha256_Raw(key, keylen, i_key_pad);
+  } else {
+    memcpy(i_key_pad, key, keylen);
+  }
+  for (int i = 0; i < SHA256_BLOCK_LENGTH; i++) {
+    hctx->o_key_pad[i] = i_key_pad[i] ^ 0x5c;
+    i_key_pad[i] ^= 0x36;
+  }
+  sha256_Init(&(hctx->ctx));
+  sha256_Update(&(hctx->ctx), i_key_pad, SHA256_BLOCK_LENGTH);
+  memzero(i_key_pad, sizeof(i_key_pad));
+}
+
+void hmac_sha256_Update(HMAC_SHA256_CTX *hctx, const uint8_t *msg,
+                        const uint32_t msglen) {
+  sha256_Update(&(hctx->ctx), msg, msglen);
+}
+
+void hmac_sha256_Final(HMAC_SHA256_CTX *hctx, uint8_t *hmac) {
+  sha256_Final(&(hctx->ctx), hmac);
+  sha256_Init(&(hctx->ctx));
+  sha256_Update(&(hctx->ctx), hctx->o_key_pad, SHA256_BLOCK_LENGTH);
+  sha256_Update(&(hctx->ctx), hmac, SHA256_DIGEST_LENGTH);
+  sha256_Final(&(hctx->ctx), hmac);
+  memzero(hctx, sizeof(HMAC_SHA256_CTX));
+}
+
+void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg,
+                 const uint32_t msglen, uint8_t *hmac) {
+  static CONFIDENTIAL HMAC_SHA256_CTX hctx;
+  hmac_sha256_Init(&hctx, key, keylen);
+  hmac_sha256_Update(&hctx, msg, msglen);
+  hmac_sha256_Final(&hctx, hmac);
+}
+
+void hmac_sha256_prepare(const uint8_t *key, const uint32_t keylen,
+                         uint32_t *opad_digest, uint32_t *ipad_digest) {
+  static CONFIDENTIAL uint32_t key_pad[SHA256_BLOCK_LENGTH / sizeof(uint32_t)];
+
+  memzero(key_pad, sizeof(key_pad));
+  if (keylen > SHA256_BLOCK_LENGTH) {
+    static CONFIDENTIAL SHA256_CTX context;
+    sha256_Init(&context);
+    sha256_Update(&context, key, keylen);
+    sha256_Final(&context, (uint8_t *)key_pad);
+  } else {
+    memcpy(key_pad, key, keylen);
+  }
+
+  /* compute o_key_pad and its digest */
+  for (int i = 0; i < SHA256_BLOCK_LENGTH / (int)sizeof(uint32_t); i++) {
+    uint32_t data = 0;
+#if BYTE_ORDER == LITTLE_ENDIAN
+    REVERSE32(key_pad[i], data);
+#else
+    data = key_pad[i];
+#endif
+    key_pad[i] = data ^ 0x5c5c5c5c;
+  }
+  sha256_Transform(sha256_initial_hash_value, key_pad, opad_digest);
+
+  /* convert o_key_pad to i_key_pad and compute its digest */
+  for (int i = 0; i < SHA256_BLOCK_LENGTH / (int)sizeof(uint32_t); i++) {
+    key_pad[i] = key_pad[i] ^ 0x5c5c5c5c ^ 0x36363636;
+  }
+  sha256_Transform(sha256_initial_hash_value, key_pad, ipad_digest);
+  memzero(key_pad, sizeof(key_pad));
+}
+
+void hmac_sha512_Init(HMAC_SHA512_CTX *hctx, const uint8_t *key,
+                      const uint32_t keylen) {
+  static CONFIDENTIAL uint8_t i_key_pad[SHA512_BLOCK_LENGTH];
+  memzero(i_key_pad, SHA512_BLOCK_LENGTH);
+  if (keylen > SHA512_BLOCK_LENGTH) {
+    sha512_Raw(key, keylen, i_key_pad);
+  } else {
+    memcpy(i_key_pad, key, keylen);
+  }
+  for (int i = 0; i < SHA512_BLOCK_LENGTH; i++) {
+    hctx->o_key_pad[i] = i_key_pad[i] ^ 0x5c;
+    i_key_pad[i] ^= 0x36;
+  }
+  sha512_Init(&(hctx->ctx));
+  sha512_Update(&(hctx->ctx), i_key_pad, SHA512_BLOCK_LENGTH);
+  memzero(i_key_pad, sizeof(i_key_pad));
+}
+
+void hmac_sha512_Update(HMAC_SHA512_CTX *hctx, const uint8_t *msg,
+                        const uint32_t msglen) {
+  sha512_Update(&(hctx->ctx), msg, msglen);
+}
+
+void hmac_sha512_Final(HMAC_SHA512_CTX *hctx, uint8_t *hmac) {
+  sha512_Final(&(hctx->ctx), hmac);
+  sha512_Init(&(hctx->ctx));
+  sha512_Update(&(hctx->ctx), hctx->o_key_pad, SHA512_BLOCK_LENGTH);
+  sha512_Update(&(hctx->ctx), hmac, SHA512_DIGEST_LENGTH);
+  sha512_Final(&(hctx->ctx), hmac);
+  memzero(hctx, sizeof(HMAC_SHA512_CTX));
+}
+
+void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg,
+                 const uint32_t msglen, uint8_t *hmac) {
+  HMAC_SHA512_CTX hctx = {0};
+  hmac_sha512_Init(&hctx, key, keylen);
+  hmac_sha512_Update(&hctx, msg, msglen);
+  hmac_sha512_Final(&hctx, hmac);
+}
+
+void hmac_sha512_prepare(const uint8_t *key, const uint32_t keylen,
+                         uint64_t *opad_digest, uint64_t *ipad_digest) {
+  static CONFIDENTIAL uint64_t key_pad[SHA512_BLOCK_LENGTH / sizeof(uint64_t)];
+
+  memzero(key_pad, sizeof(key_pad));
+  if (keylen > SHA512_BLOCK_LENGTH) {
+    static CONFIDENTIAL SHA512_CTX context;
+    sha512_Init(&context);
+    sha512_Update(&context, key, keylen);
+    sha512_Final(&context, (uint8_t *)key_pad);
+  } else {
+    memcpy(key_pad, key, keylen);
+  }
+
+  /* compute o_key_pad and its digest */
+  for (int i = 0; i < SHA512_BLOCK_LENGTH / (int)sizeof(uint64_t); i++) {
+    uint64_t data = 0;
+#if BYTE_ORDER == LITTLE_ENDIAN
+    REVERSE64(key_pad[i], data);
+#else
+    data = key_pad[i];
+#endif
+    key_pad[i] = data ^ 0x5c5c5c5c5c5c5c5c;
+  }
+  sha512_Transform(sha512_initial_hash_value, key_pad, opad_digest);
+
+  /* convert o_key_pad to i_key_pad and compute its digest */
+  for (int i = 0; i < SHA512_BLOCK_LENGTH / (int)sizeof(uint64_t); i++) {
+    key_pad[i] = key_pad[i] ^ 0x5c5c5c5c5c5c5c5c ^ 0x3636363636363636;
+  }
+  sha512_Transform(sha512_initial_hash_value, key_pad, ipad_digest);
+  memzero(key_pad, sizeof(key_pad));
+}

Некоторые файлы не были показаны из-за большого количества измененных файлов