From 833c56db0159eee5544d3af52bc43f5d006c361a Mon Sep 17 00:00:00 2001
From: Dmitriy Gerasimov <dm@cifercom.com>
Date: Wed, 27 Dec 2017 11:47:18 +0700
Subject: [PATCH] [+] monero crypto subsytem for classic postqantum-proofed
 alghorythms, including "Slow-Hash" for mining

---
 crypt/monero_crypto/CMakeLists.txt            |  102 +
 crypt/monero_crypto/aesb.c                    |  185 +
 crypt/monero_crypto/blake256.c                |  355 ++
 crypt/monero_crypto/blake256.h                |   73 +
 crypt/monero_crypto/chacha8.c                 |  170 +
 crypt/monero_crypto/chacha8.h                 |   79 +
 crypt/monero_crypto/crypto-ops-data.c         |  872 ++++
 crypt/monero_crypto/crypto-ops.c              | 3580 +++++++++++++++++
 crypt/monero_crypto/crypto-ops.h              |  156 +
 crypt/monero_crypto/crypto.cpp                |  564 +++
 crypt/monero_crypto/crypto.h                  |  289 ++
 .../monero_crypto/crypto_ops_builder/Makefile |   10 +
 .../crypto_ops_builder/README.md              |   21 +
 crypt/monero_crypto/crypto_ops_builder/api.h  |    2 +
 .../crypto_ops_builder/crypto-ops-data.c      |  872 ++++
 .../crypto_ops_builder/crypto-ops-old.c       | 3008 ++++++++++++++
 .../crypto_ops_builder/crypto-ops.h           |  148 +
 .../crypto_ops_builder/crypto_int32.h         |    6 +
 .../crypto_ops_builder/crypto_sign.h          |   13 +
 .../crypto_ops_builder/crypto_uint32.h        |    6 +
 .../crypto_ops_builder/crypto_verify_32.h     |    7 +
 .../monero_crypto/crypto_ops_builder/ietf.txt | 1402 +++++++
 .../crypto_ops_builder/include/Makefile.am    |   62 +
 .../include/libsodium_LICENSE                 |   16 +
 .../crypto_ops_builder/include/sodium.h       |   50 +
 .../include/sodium/crypto_int32.h             |    8 +
 .../include/sodium/crypto_int64.h             |    8 +
 .../include/sodium/crypto_uint16.h            |    8 +
 .../include/sodium/crypto_uint32.h            |    8 +
 .../include/sodium/crypto_uint64.h            |    8 +
 .../include/sodium/crypto_uint8.h             |    8 +
 .../include/sodium/crypto_verify_32.h         |   22 +
 .../include/sodium/randombytes.h              |   58 +
 .../crypto_ops_builder/randombytes.c          |   52 +
 .../crypto_ops_builder/ref10/Makefile         |   41 +
 .../crypto_ops_builder/ref10/api.h            |    4 +
 .../crypto_ops_builder/ref10/base.h           | 1344 +++++++
 .../crypto_ops_builder/ref10/base.py          |   65 +
 .../crypto_ops_builder/ref10/base2.h          |   40 +
 .../crypto_ops_builder/ref10/base2.py         |   60 +
 .../crypto_ops_builder/ref10/d.h              |    1 +
 .../crypto_ops_builder/ref10/d.py             |   28 +
 .../crypto_ops_builder/ref10/d2.h             |    1 +
 .../crypto_ops_builder/ref10/d2.py            |   28 +
 .../crypto_ops_builder/ref10/description      |    2 +
 .../crypto_ops_builder/ref10/designers        |    5 +
 .../crypto_ops_builder/ref10/fe.h             |   56 +
 .../crypto_ops_builder/ref10/fe_0.c           |   19 +
 .../crypto_ops_builder/ref10/fe_1.c           |   19 +
 .../crypto_ops_builder/ref10/fe_add.c         |   57 +
 .../crypto_ops_builder/ref10/fe_cmov.c        |   63 +
 .../crypto_ops_builder/ref10/fe_copy.c        |   29 +
 .../crypto_ops_builder/ref10/fe_frombytes.c   |   73 +
 .../crypto_ops_builder/ref10/fe_invert.c      |   14 +
 .../crypto_ops_builder/ref10/fe_isnegative.c  |   16 +
 .../crypto_ops_builder/ref10/fe_isnonzero.c   |   19 +
 .../crypto_ops_builder/ref10/fe_mul.c         |  253 ++
 .../crypto_ops_builder/ref10/fe_neg.c         |   45 +
 .../crypto_ops_builder/ref10/fe_pow22523.c    |   13 +
 .../crypto_ops_builder/ref10/fe_sq.c          |  149 +
 .../crypto_ops_builder/ref10/fe_sq2.c         |  160 +
 .../crypto_ops_builder/ref10/fe_sub.c         |   57 +
 .../crypto_ops_builder/ref10/fe_tobytes.c     |  119 +
 .../crypto_ops_builder/ref10/ge.h             |   95 +
 .../crypto_ops_builder/ref10/ge_add.c         |   11 +
 .../crypto_ops_builder/ref10/ge_add.h         |   97 +
 .../crypto_ops_builder/ref10/ge_add.q         |   49 +
 .../ref10/ge_double_scalarmult.c              |   96 +
 .../crypto_ops_builder/ref10/ge_frombytes.c   |   50 +
 .../crypto_ops_builder/ref10/ge_madd.c        |   11 +
 .../crypto_ops_builder/ref10/ge_madd.h        |   88 +
 .../crypto_ops_builder/ref10/ge_madd.q        |   46 +
 .../crypto_ops_builder/ref10/ge_msub.c        |   11 +
 .../crypto_ops_builder/ref10/ge_msub.h        |   88 +
 .../crypto_ops_builder/ref10/ge_msub.q        |   46 +
 .../crypto_ops_builder/ref10/ge_p1p1_to_p2.c  |   12 +
 .../crypto_ops_builder/ref10/ge_p1p1_to_p3.c  |   13 +
 .../crypto_ops_builder/ref10/ge_p2_0.c        |    8 +
 .../crypto_ops_builder/ref10/ge_p2_dbl.c      |   11 +
 .../crypto_ops_builder/ref10/ge_p2_dbl.h      |   73 +
 .../crypto_ops_builder/ref10/ge_p2_dbl.q      |   41 +
 .../crypto_ops_builder/ref10/ge_p3_0.c        |    9 +
 .../crypto_ops_builder/ref10/ge_p3_dbl.c      |   12 +
 .../ref10/ge_p3_to_cached.c                   |   17 +
 .../crypto_ops_builder/ref10/ge_p3_to_p2.c    |   12 +
 .../crypto_ops_builder/ref10/ge_p3_tobytes.c  |   14 +
 .../crypto_ops_builder/ref10/ge_precomp_0.c   |    8 +
 .../ref10/ge_scalarmult_base.c                |  105 +
 .../crypto_ops_builder/ref10/ge_sub.c         |   11 +
 .../crypto_ops_builder/ref10/ge_sub.h         |   97 +
 .../crypto_ops_builder/ref10/ge_sub.q         |   49 +
 .../crypto_ops_builder/ref10/ge_tobytes.c     |   14 +
 .../crypto_ops_builder/ref10/keypair.c        |   23 +
 .../crypto_ops_builder/ref10/open.c           |   48 +
 .../crypto_ops_builder/ref10/pow22523.h       |  160 +
 .../crypto_ops_builder/ref10/pow22523.q       |   61 +
 .../crypto_ops_builder/ref10/pow225521.h      |  160 +
 .../crypto_ops_builder/ref10/pow225521.q      |   61 +
 .../crypto_ops_builder/ref10/q2h.sh           |    4 +
 .../crypto_ops_builder/ref10/sc.h             |   15 +
 .../crypto_ops_builder/ref10/sc_muladd.c      |  368 ++
 .../crypto_ops_builder/ref10/sc_reduce.c      |  275 ++
 .../crypto_ops_builder/ref10/sign.c           |   41 +
 .../crypto_ops_builder/ref10/sqrtm1.h         |    1 +
 .../crypto_ops_builder/ref10/sqrtm1.py        |   28 +
 .../ref10CommentedCombined/MakeCryptoOps.py   |  261 ++
 .../ref10CommentedCombined/api.h              |    4 +
 .../ref10CommentedCombined/base.h             | 1344 +++++++
 .../ref10CommentedCombined/base.py            |   65 +
 .../ref10CommentedCombined/base2.h            |   40 +
 .../ref10CommentedCombined/base2.py           |   60 +
 .../ref10CommentedCombined/crypto-ops.h       |  145 +
 .../ref10CommentedCombined/d.h                |    1 +
 .../ref10CommentedCombined/d.py               |   28 +
 .../ref10CommentedCombined/d2.h               |    1 +
 .../ref10CommentedCombined/d2.py              |   28 +
 .../ref10CommentedCombined/description        |    7 +
 .../ref10CommentedCombined/designers          |    9 +
 .../ref10CommentedCombined/fe.h               |   56 +
 .../ref10CommentedCombined/fe_0.c             |   19 +
 .../ref10CommentedCombined/fe_1.c             |   19 +
 .../ref10CommentedCombined/fe_add.c           |   57 +
 .../ref10CommentedCombined/fe_cmov.c          |   63 +
 .../ref10CommentedCombined/fe_copy.c          |   29 +
 .../ref10CommentedCombined/fe_frombytes.c     |   73 +
 .../ref10CommentedCombined/fe_invert.c        |   14 +
 .../ref10CommentedCombined/fe_isnegative.c    |   16 +
 .../ref10CommentedCombined/fe_isnonzero.c     |   19 +
 .../ref10CommentedCombined/fe_mul.c           |  253 ++
 .../ref10CommentedCombined/fe_neg.c           |   45 +
 .../ref10CommentedCombined/fe_pow22523.c      |   13 +
 .../ref10CommentedCombined/fe_sq.c            |  149 +
 .../ref10CommentedCombined/fe_sq2.c           |  160 +
 .../ref10CommentedCombined/fe_sub.c           |   57 +
 .../ref10CommentedCombined/fe_tobytes.c       |  119 +
 .../ref10CommentedCombined/ge.h               |   95 +
 .../ref10CommentedCombined/ge_add.c           |   11 +
 .../ref10CommentedCombined/ge_add.h           |   97 +
 .../ref10CommentedCombined/ge_add.q           |   49 +
 .../ge_double_scalarmult.c                    |   96 +
 .../ref10CommentedCombined/ge_frombytes.c     |   50 +
 .../ref10CommentedCombined/ge_madd.c          |   11 +
 .../ref10CommentedCombined/ge_madd.h          |   88 +
 .../ref10CommentedCombined/ge_madd.q          |   46 +
 .../ref10CommentedCombined/ge_msub.c          |   11 +
 .../ref10CommentedCombined/ge_msub.h          |   88 +
 .../ref10CommentedCombined/ge_msub.q          |   46 +
 .../ref10CommentedCombined/ge_p1p1_to_p2.c    |   12 +
 .../ref10CommentedCombined/ge_p1p1_to_p3.c    |   13 +
 .../ref10CommentedCombined/ge_p2_0.c          |    8 +
 .../ref10CommentedCombined/ge_p2_dbl.c        |   11 +
 .../ref10CommentedCombined/ge_p2_dbl.h        |   73 +
 .../ref10CommentedCombined/ge_p2_dbl.q        |   41 +
 .../ref10CommentedCombined/ge_p3_0.c          |    9 +
 .../ref10CommentedCombined/ge_p3_dbl.c        |   12 +
 .../ref10CommentedCombined/ge_p3_to_cached.c  |   17 +
 .../ref10CommentedCombined/ge_p3_to_p2.c      |   12 +
 .../ref10CommentedCombined/ge_p3_tobytes.c    |   14 +
 .../ref10CommentedCombined/ge_precomp_0.c     |    8 +
 .../ge_scalarmult_base.c                      |  105 +
 .../ref10CommentedCombined/ge_sub.c           |   11 +
 .../ref10CommentedCombined/ge_sub.h           |   97 +
 .../ref10CommentedCombined/ge_sub.q           |   49 +
 .../ref10CommentedCombined/ge_tobytes.c       |   14 +
 .../ref10CommentedCombined/keypair.c          |   23 +
 .../ref10CommentedCombined/open.c             |   48 +
 .../ref10CommentedCombined/pow22523.h         |  160 +
 .../ref10CommentedCombined/pow22523.q         |   61 +
 .../ref10CommentedCombined/pow225521.h        |  160 +
 .../ref10CommentedCombined/pow225521.q        |   61 +
 .../ref10CommentedCombined/q2h.sh             |    4 +
 .../ref10CommentedCombined/sc.h               |   15 +
 .../ref10CommentedCombined/sc_muladd.c        |  368 ++
 .../ref10CommentedCombined/sc_reduce.c        |  275 ++
 .../ref10CommentedCombined/sc_sub.xmr.c       |  504 +++
 .../ref10CommentedCombined/scrap.txt          |   53 +
 .../ref10CommentedCombined/sign.c             |   41 +
 .../ref10CommentedCombined/sqrtm1.h           |    1 +
 .../ref10CommentedCombined/sqrtm1.py          |   28 +
 .../ref10CommentedCombined/test.py            |    5 +
 .../ref10CommentedCombined/xmrSpecificOld.c   |  776 ++++
 .../crypto_ops_builder/sha512-blocks.c        |  239 ++
 .../crypto_ops_builder/sha512-hash.c          |   72 +
 .../monero_crypto/crypto_ops_builder/sha512.h |    4 +
 .../monero_crypto/crypto_ops_builder/verify.c |   40 +
 crypt/monero_crypto/generic-ops.h             |   62 +
 crypt/monero_crypto/groestl.c                 |  360 ++
 crypt/monero_crypto/groestl.h                 |   88 +
 crypt/monero_crypto/groestl_tables.h          |   66 +
 crypt/monero_crypto/hash-extra-blake.c        |   38 +
 crypt/monero_crypto/hash-extra-groestl.c      |   38 +
 crypt/monero_crypto/hash-extra-jh.c           |   42 +
 crypt/monero_crypto/hash-extra-skein.c        |   40 +
 crypt/monero_crypto/hash-ops.h                |   89 +
 crypt/monero_crypto/hash.c                    |   50 +
 crypt/monero_crypto/hash.h                    |   94 +
 crypt/monero_crypto/initializer.h             |   63 +
 crypt/{hash => monero_crypto}/jh.c            |    0
 crypt/{hash => monero_crypto}/jh.h            |    0
 crypt/{hash => monero_crypto}/keccak.c        |    0
 crypt/{hash => monero_crypto}/keccak.h        |    0
 crypt/monero_crypto/oaes_config.h             |   50 +
 crypt/{ => monero_crypto}/oaes_lib.c          |    0
 crypt/{ => monero_crypto}/oaes_lib.h          |    0
 crypt/monero_crypto/random.c                  |  143 +
 crypt/monero_crypto/random.h                  |   35 +
 crypt/monero_crypto/skein.c                   | 2036 ++++++++++
 crypt/monero_crypto/skein.h                   |   47 +
 crypt/monero_crypto/skein_port.h              |  218 +
 crypt/monero_crypto/slow-hash.c               | 1284 ++++++
 crypt/monero_crypto/tree-hash.c               |  111 +
 211 files changed, 29687 insertions(+)
 create mode 100644 crypt/monero_crypto/CMakeLists.txt
 create mode 100644 crypt/monero_crypto/aesb.c
 create mode 100644 crypt/monero_crypto/blake256.c
 create mode 100644 crypt/monero_crypto/blake256.h
 create mode 100644 crypt/monero_crypto/chacha8.c
 create mode 100644 crypt/monero_crypto/chacha8.h
 create mode 100644 crypt/monero_crypto/crypto-ops-data.c
 create mode 100644 crypt/monero_crypto/crypto-ops.c
 create mode 100644 crypt/monero_crypto/crypto-ops.h
 create mode 100644 crypt/monero_crypto/crypto.cpp
 create mode 100644 crypt/monero_crypto/crypto.h
 create mode 100755 crypt/monero_crypto/crypto_ops_builder/Makefile
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/README.md
 create mode 100755 crypt/monero_crypto/crypto_ops_builder/api.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/crypto-ops-data.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/crypto-ops-old.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/crypto-ops.h
 create mode 100755 crypt/monero_crypto/crypto_ops_builder/crypto_int32.h
 create mode 100755 crypt/monero_crypto/crypto_ops_builder/crypto_sign.h
 create mode 100755 crypt/monero_crypto/crypto_ops_builder/crypto_uint32.h
 create mode 100755 crypt/monero_crypto/crypto_ops_builder/crypto_verify_32.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ietf.txt
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/include/Makefile.am
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/include/libsodium_LICENSE
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/include/sodium.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/include/sodium/crypto_int32.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/include/sodium/crypto_int64.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/include/sodium/crypto_uint16.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/include/sodium/crypto_uint32.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/include/sodium/crypto_uint64.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/include/sodium/crypto_uint8.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/include/sodium/crypto_verify_32.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/include/sodium/randombytes.h
 create mode 100755 crypt/monero_crypto/crypto_ops_builder/randombytes.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/Makefile
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/api.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/base.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/base.py
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/base2.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/base2.py
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/d.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/d.py
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/d2.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/d2.py
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/description
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/designers
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/fe.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/fe_0.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/fe_1.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/fe_add.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/fe_cmov.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/fe_copy.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/fe_frombytes.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/fe_invert.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/fe_isnegative.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/fe_isnonzero.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/fe_mul.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/fe_neg.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/fe_pow22523.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/fe_sq.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/fe_sq2.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/fe_sub.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/fe_tobytes.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/ge.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/ge_add.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/ge_add.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/ge_add.q
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/ge_double_scalarmult.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/ge_frombytes.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/ge_madd.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/ge_madd.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/ge_madd.q
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/ge_msub.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/ge_msub.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/ge_msub.q
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/ge_p1p1_to_p2.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/ge_p1p1_to_p3.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/ge_p2_0.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/ge_p2_dbl.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/ge_p2_dbl.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/ge_p2_dbl.q
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/ge_p3_0.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/ge_p3_dbl.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/ge_p3_to_cached.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/ge_p3_to_p2.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/ge_p3_tobytes.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/ge_precomp_0.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/ge_scalarmult_base.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/ge_sub.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/ge_sub.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/ge_sub.q
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/ge_tobytes.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/keypair.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/open.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/pow22523.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/pow22523.q
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/pow225521.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/pow225521.q
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/q2h.sh
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/sc.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/sc_muladd.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/sc_reduce.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/sign.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/sqrtm1.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10/sqrtm1.py
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/MakeCryptoOps.py
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/api.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/base.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/base.py
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/base2.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/base2.py
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/crypto-ops.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/d.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/d.py
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/d2.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/d2.py
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/description
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/designers
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_0.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_1.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_add.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_cmov.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_copy.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_frombytes.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_invert.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_isnegative.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_isnonzero.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_mul.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_neg.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_pow22523.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_sq.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_sq2.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_sub.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_tobytes.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_add.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_add.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_add.q
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_double_scalarmult.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_frombytes.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_madd.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_madd.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_madd.q
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_msub.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_msub.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_msub.q
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p1p1_to_p2.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p1p1_to_p3.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p2_0.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p2_dbl.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p2_dbl.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p2_dbl.q
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p3_0.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p3_dbl.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p3_to_cached.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p3_to_p2.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p3_tobytes.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_precomp_0.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_scalarmult_base.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_sub.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_sub.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_sub.q
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_tobytes.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/keypair.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/open.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/pow22523.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/pow22523.q
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/pow225521.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/pow225521.q
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/q2h.sh
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sc.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sc_muladd.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sc_reduce.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sc_sub.xmr.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/scrap.txt
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sign.c
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sqrtm1.h
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sqrtm1.py
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/test.py
 create mode 100644 crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/xmrSpecificOld.c
 create mode 100755 crypt/monero_crypto/crypto_ops_builder/sha512-blocks.c
 create mode 100755 crypt/monero_crypto/crypto_ops_builder/sha512-hash.c
 create mode 100755 crypt/monero_crypto/crypto_ops_builder/sha512.h
 create mode 100755 crypt/monero_crypto/crypto_ops_builder/verify.c
 create mode 100644 crypt/monero_crypto/generic-ops.h
 create mode 100644 crypt/monero_crypto/groestl.c
 create mode 100644 crypt/monero_crypto/groestl.h
 create mode 100644 crypt/monero_crypto/groestl_tables.h
 create mode 100644 crypt/monero_crypto/hash-extra-blake.c
 create mode 100644 crypt/monero_crypto/hash-extra-groestl.c
 create mode 100644 crypt/monero_crypto/hash-extra-jh.c
 create mode 100644 crypt/monero_crypto/hash-extra-skein.c
 create mode 100644 crypt/monero_crypto/hash-ops.h
 create mode 100644 crypt/monero_crypto/hash.c
 create mode 100644 crypt/monero_crypto/hash.h
 create mode 100644 crypt/monero_crypto/initializer.h
 rename crypt/{hash => monero_crypto}/jh.c (100%)
 rename crypt/{hash => monero_crypto}/jh.h (100%)
 rename crypt/{hash => monero_crypto}/keccak.c (100%)
 rename crypt/{hash => monero_crypto}/keccak.h (100%)
 create mode 100644 crypt/monero_crypto/oaes_config.h
 rename crypt/{ => monero_crypto}/oaes_lib.c (100%)
 rename crypt/{ => monero_crypto}/oaes_lib.h (100%)
 create mode 100644 crypt/monero_crypto/random.c
 create mode 100644 crypt/monero_crypto/random.h
 create mode 100644 crypt/monero_crypto/skein.c
 create mode 100644 crypt/monero_crypto/skein.h
 create mode 100644 crypt/monero_crypto/skein_port.h
 create mode 100644 crypt/monero_crypto/slow-hash.c
 create mode 100644 crypt/monero_crypto/tree-hash.c

diff --git a/crypt/monero_crypto/CMakeLists.txt b/crypt/monero_crypto/CMakeLists.txt
new file mode 100644
index 0000000000..1e06a0dfd0
--- /dev/null
+++ b/crypt/monero_crypto/CMakeLists.txt
@@ -0,0 +1,102 @@
+# 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.
+
+set(crypto_sources
+  aesb.c
+  blake256.c
+  chacha8.c
+  crypto-ops-data.c
+  crypto-ops.c
+  crypto.cpp
+  groestl.c
+  hash-extra-blake.c
+  hash-extra-groestl.c
+  hash-extra-jh.c
+  hash-extra-skein.c
+  hash.c
+  jh.c
+  keccak.c
+  oaes_lib.c
+  random.c
+  skein.c
+  slow-hash.c
+  tree-hash.c)
+
+set(crypto_headers)
+
+set(crypto_private_headers
+  blake256.h
+  chacha8.h
+  crypto-ops.h
+  crypto.h
+  generic-ops.h
+  groestl.h
+  groestl_tables.h
+  hash-ops.h
+  hash.h
+  initializer.h
+  jh.h
+  keccak.h
+  oaes_config.h
+  oaes_lib.h
+  random.h
+  skein.h
+  skein_port.h)
+
+monero_private_headers(cncrypto
+  ${crypto_private_headers})
+monero_add_library(cncrypto
+  ${crypto_sources}
+  ${crypto_headers}
+  ${crypto_private_headers})
+target_link_libraries(cncrypto
+  PUBLIC
+    ${Boost_SYSTEM_LIBRARY}
+  PRIVATE
+    ${EXTRA_LIBRARIES})
+
+if (ARM)
+  option(NO_OPTIMIZED_MULTIPLY_ON_ARM
+	   "Compute multiply using generic C implementation instead of ARM ASM" OFF)
+  if(NO_OPTIMIZED_MULTIPLY_ON_ARM)
+    message(STATUS "Using generic C implementation for multiply")
+    set_property(SOURCE slow-hash.c
+      PROPERTY COMPILE_DEFINITIONS "NO_OPTIMIZED_MULTIPLY_ON_ARM")
+  endif()
+endif()
+
+# Because of the way Qt works on android with JNI, the code does not live in the main android thread
+# So this code runs with a 1 MB default stack size. 
+# This will force the use of the heap for the allocation of the scratchpad
+if (ANDROID OR IOS)
+  if( BUILD_GUI_DEPS )
+    add_definitions(-DFORCE_USE_HEAP=1)
+  endif()
+endif()
+
+
diff --git a/crypt/monero_crypto/aesb.c b/crypt/monero_crypto/aesb.c
new file mode 100644
index 0000000000..5d57b8af4b
--- /dev/null
+++ b/crypt/monero_crypto/aesb.c
@@ -0,0 +1,185 @@
+/*
+---------------------------------------------------------------------------
+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 <stdint.h>
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+#define TABLE_ALIGN     32
+#define WPOLY           0x011b
+#define N_COLS          4
+#define AES_BLOCK_SIZE  16
+#define RC_LENGTH       (5 * (AES_BLOCK_SIZE / 4 - 2))
+
+#if defined(_MSC_VER)
+#define ALIGN __declspec(align(TABLE_ALIGN))
+#elif defined(__GNUC__)
+#define ALIGN __attribute__ ((aligned(16)))
+#else
+#define ALIGN
+#endif
+
+#define rf1(r,c) (r)
+#define word_in(x,c) (*((uint32_t*)(x)+(c)))
+#define word_out(x,c,v) (*((uint32_t*)(x)+(c)) = (v))
+
+#define s(x,c) x[c]
+#define si(y,x,c) (s(y,c) = word_in(x, c))
+#define so(y,x,c) word_out(y, c, s(x,c))
+#define state_in(y,x) si(y,x,0); si(y,x,1); si(y,x,2); si(y,x,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)
+#define to_byte(x) ((x) & 0xff)
+#define bval(x,n) to_byte((x) >> (8 * (n)))
+
+#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)))
+
+#define fwd_rnd(y,x,k,c)  (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,n),fwd_var,rf1,c))
+
+#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 rc_data(w) {\
+  w(0x01), w(0x02), w(0x04), w(0x08), w(0x10),w(0x20), w(0x40), w(0x80),\
+  w(0x1b), w(0x36) }
+
+#define bytes2word(b0, b1, b2, b3) (((uint32_t)(b3) << 24) | \
+    ((uint32_t)(b2) << 16) | ((uint32_t)(b1) << 8) | (b0))
+
+#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))
+
+#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))
+
+#define t_dec(m,n) t_##m##n
+#define t_set(m,n) t_##m##n
+#define t_use(m,n) t_##m##n
+
+#define d_4(t,n,b,e,f,g,h) ALIGN const t n[4][256] = { b(e), b(f), b(g), b(h) }
+
+#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))])
+
+d_4(uint32_t, t_dec(f,n), sb_data, u0, u1, u2, u3);
+
+#if !defined(STATIC)
+#define STATIC
+#endif
+
+#if !defined(INLINE)
+#define INLINE
+#endif
+
+STATIC INLINE void aesb_single_round(const uint8_t *in, uint8_t *out, uint8_t *expandedKey)
+{
+  uint32_t b0[4], b1[4];
+  const uint32_t  *kp = (uint32_t *) expandedKey;
+  state_in(b0, in);
+
+  round(fwd_rnd,  b1, b0, kp);
+
+  state_out(out, b1);
+}
+
+STATIC INLINE void aesb_pseudo_round(const uint8_t *in, uint8_t *out, uint8_t *expandedKey)
+{
+  uint32_t b0[4], b1[4];
+  const uint32_t  *kp = (uint32_t *) expandedKey;
+  state_in(b0, in);
+
+  round(fwd_rnd,  b1, b0, kp);
+  round(fwd_rnd,  b0, b1, kp + 1 * N_COLS);
+  round(fwd_rnd,  b1, b0, kp + 2 * N_COLS);
+  round(fwd_rnd,  b0, b1, kp + 3 * N_COLS);
+  round(fwd_rnd,  b1, b0, kp + 4 * N_COLS);
+  round(fwd_rnd,  b0, b1, kp + 5 * N_COLS);
+  round(fwd_rnd,  b1, b0, kp + 6 * N_COLS);
+  round(fwd_rnd,  b0, b1, kp + 7 * N_COLS);
+  round(fwd_rnd,  b1, b0, kp + 8 * N_COLS);
+  round(fwd_rnd,  b0, b1, kp + 9 * N_COLS);
+
+  state_out(out, b0);
+}
+
+
+#if defined(__cplusplus)
+}
+#endif
diff --git a/crypt/monero_crypto/blake256.c b/crypt/monero_crypto/blake256.c
new file mode 100644
index 0000000000..1e43f9c4d9
--- /dev/null
+++ b/crypt/monero_crypto/blake256.c
@@ -0,0 +1,355 @@
+// 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.
+// 
+
+/*
+ * The blake256_* and blake224_* functions are largely copied from
+ * blake256_light.c and blake224_light.c from the BLAKE website:
+ *
+ *     http://131002.net/blake/
+ *
+ * The hmac_* functions implement HMAC-BLAKE-256 and HMAC-BLAKE-224.
+ * HMAC is specified by RFC 2104.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdint.h>
+#include "blake256.h"
+
+#define U8TO32(p) \
+    (((uint32_t)((p)[0]) << 24) | ((uint32_t)((p)[1]) << 16) |    \
+     ((uint32_t)((p)[2]) <<  8) | ((uint32_t)((p)[3])      ))
+#define U32TO8(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)      );
+
+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}
+};
+
+const uint32_t cst[16] = {
+    0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344,
+    0xA4093822, 0x299F31D0, 0x082EFA98, 0xEC4E6C89,
+    0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C,
+    0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917
+};
+
+static const uint8_t padding[] = {
+    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
+};
+
+
+void blake256_compress(state *S, const uint8_t *block) {
+    uint32_t v[16], m[16], i;
+
+#define ROT(x,n) (((x)<<(32-n))|((x)>>(n)))
+#define G(a,b,c,d,e)                                      \
+    v[a] += (m[sigma[i][e]] ^ cst[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]] ^ cst[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(block + i * 4);
+    for (i = 0; i < 8;  ++i) v[i] = S->h[i];
+    v[ 8] = S->s[0] ^ 0x243F6A88;
+    v[ 9] = S->s[1] ^ 0x85A308D3;
+    v[10] = S->s[2] ^ 0x13198A2E;
+    v[11] = S->s[3] ^ 0x03707344;
+    v[12] = 0xA4093822;
+    v[13] = 0x299F31D0;
+    v[14] = 0x082EFA98;
+    v[15] = 0xEC4E6C89;
+
+    if (S->nullt == 0) {
+        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) {
+        G(0, 4,  8, 12,  0);
+        G(1, 5,  9, 13,  2);
+        G(2, 6, 10, 14,  4);
+        G(3, 7, 11, 15,  6);
+        G(3, 4,  9, 14, 14);
+        G(2, 7,  8, 13, 12);
+        G(0, 5, 10, 15,  8);
+        G(1, 6, 11, 12, 10);
+    }
+
+    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(state *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 blake224_init(state *S) {
+    S->h[0] = 0xC1059ED8;
+    S->h[1] = 0x367CD507;
+    S->h[2] = 0x3070DD17;
+    S->h[3] = 0xF70E5939;
+    S->h[4] = 0xFFC00B31;
+    S->h[5] = 0x68581511;
+    S->h[6] = 0x64F98FA7;
+    S->h[7] = 0xBEFA4FA4;
+    S->t[0] = S->t[1] = S->buflen = S->nullt = 0;
+    S->s[0] = S->s[1] = S->s[2] = S->s[3] = 0;
+}
+
+// datalen = number of bits
+void blake256_update(state *S, const uint8_t *data, uint64_t datalen) {
+    int left = S->buflen >> 3;
+    int fill = 64 - left;
+
+    if (left && (((datalen >> 3) & 0x3F) >= (unsigned) fill)) {
+        memcpy((void *) (S->buf + left), (void *) data, fill);
+        S->t[0] += 512;
+        if (S->t[0] == 0) S->t[1]++;
+        blake256_compress(S, S->buf);
+        data += fill;
+        datalen -= (fill << 3);
+        left = 0;
+    }
+
+    while (datalen >= 512) {
+        S->t[0] += 512;
+        if (S->t[0] == 0) S->t[1]++;
+        blake256_compress(S, data);
+        data += 64;
+        datalen -= 512;
+    }
+
+    if (datalen > 0) {
+        memcpy((void *) (S->buf + left), (void *) data, datalen >> 3);
+        S->buflen = (left << 3) + datalen;
+    } else {
+        S->buflen = 0;
+    }
+}
+
+// datalen = number of bits
+void blake224_update(state *S, const uint8_t *data, uint64_t datalen) {
+    blake256_update(S, data, datalen);
+}
+
+void blake256_final_h(state *S, uint8_t *digest, uint8_t pa, uint8_t pb) {
+    uint8_t msglen[8];
+    uint32_t lo = S->t[0] + S->buflen, hi = S->t[1];
+    if (lo < (unsigned) S->buflen) hi++;
+    U32TO8(msglen + 0, hi);
+    U32TO8(msglen + 4, lo);
+
+    if (S->buflen == 440) { /* one padding byte */
+        S->t[0] -= 8;
+        blake256_update(S, &pa, 8);
+    } else {
+        if (S->buflen < 440) { /* enough space to fill the block  */
+            if (S->buflen == 0) S->nullt = 1;
+            S->t[0] -= 440 - S->buflen;
+            blake256_update(S, padding, 440 - S->buflen);
+        } else { /* need 2 compressions */
+            S->t[0] -= 512 - S->buflen;
+            blake256_update(S, padding, 512 - S->buflen);
+            S->t[0] -= 440;
+            blake256_update(S, padding + 1, 440);
+            S->nullt = 1;
+        }
+        blake256_update(S, &pb, 8);
+        S->t[0] -= 8;
+    }
+    S->t[0] -= 64;
+    blake256_update(S, msglen, 64);
+
+    U32TO8(digest +  0, S->h[0]);
+    U32TO8(digest +  4, S->h[1]);
+    U32TO8(digest +  8, S->h[2]);
+    U32TO8(digest + 12, S->h[3]);
+    U32TO8(digest + 16, S->h[4]);
+    U32TO8(digest + 20, S->h[5]);
+    U32TO8(digest + 24, S->h[6]);
+    U32TO8(digest + 28, S->h[7]);
+}
+
+void blake256_final(state *S, uint8_t *digest) {
+    blake256_final_h(S, digest, 0x81, 0x01);
+}
+
+void blake224_final(state *S, uint8_t *digest) {
+    blake256_final_h(S, digest, 0x80, 0x00);
+}
+
+// inlen = number of bytes
+void blake256_hash(uint8_t *out, const uint8_t *in, uint64_t inlen) {
+    state S;
+    blake256_init(&S);
+    blake256_update(&S, in, inlen * 8);
+    blake256_final(&S, out);
+}
+
+// inlen = number of bytes
+void blake224_hash(uint8_t *out, const uint8_t *in, uint64_t inlen) {
+    state S;
+    blake224_init(&S);
+    blake224_update(&S, in, inlen * 8);
+    blake224_final(&S, out);
+}
+
+// keylen = number of bytes
+void hmac_blake256_init(hmac_state *S, const uint8_t *_key, uint64_t keylen) {
+    const uint8_t *key = _key;
+    uint8_t keyhash[32];
+    uint8_t pad[64];
+    uint64_t i;
+
+    if (keylen > 64) {
+        blake256_hash(keyhash, key, keylen);
+        key = keyhash;
+        keylen = 32;
+    }
+
+    blake256_init(&S->inner);
+    memset(pad, 0x36, 64);
+    for (i = 0; i < keylen; ++i) {
+        pad[i] ^= key[i];
+    }
+    blake256_update(&S->inner, pad, 512);
+
+    blake256_init(&S->outer);
+    memset(pad, 0x5c, 64);
+    for (i = 0; i < keylen; ++i) {
+        pad[i] ^= key[i];
+    }
+    blake256_update(&S->outer, pad, 512);
+
+    memset(keyhash, 0, 32);
+}
+
+// keylen = number of bytes
+void hmac_blake224_init(hmac_state *S, const uint8_t *_key, uint64_t keylen) {
+    const uint8_t *key = _key;
+    uint8_t keyhash[32];
+    uint8_t pad[64];
+    uint64_t i;
+
+    if (keylen > 64) {
+        blake256_hash(keyhash, key, keylen);
+        key = keyhash;
+        keylen = 28;
+    }
+
+    blake224_init(&S->inner);
+    memset(pad, 0x36, 64);
+    for (i = 0; i < keylen; ++i) {
+        pad[i] ^= key[i];
+    }
+    blake224_update(&S->inner, pad, 512);
+
+    blake224_init(&S->outer);
+    memset(pad, 0x5c, 64);
+    for (i = 0; i < keylen; ++i) {
+        pad[i] ^= key[i];
+    }
+    blake224_update(&S->outer, pad, 512);
+
+    memset(keyhash, 0, 32);
+}
+
+// datalen = number of bits
+void hmac_blake256_update(hmac_state *S, const uint8_t *data, uint64_t datalen) {
+  // update the inner state
+  blake256_update(&S->inner, data, datalen);
+}
+
+// datalen = number of bits
+void hmac_blake224_update(hmac_state *S, const uint8_t *data, uint64_t datalen) {
+  // update the inner state
+  blake224_update(&S->inner, data, datalen);
+}
+
+void hmac_blake256_final(hmac_state *S, uint8_t *digest) {
+    uint8_t ihash[32];
+    blake256_final(&S->inner, ihash);
+    blake256_update(&S->outer, ihash, 256);
+    blake256_final(&S->outer, digest);
+    memset(ihash, 0, 32);
+}
+
+void hmac_blake224_final(hmac_state *S, uint8_t *digest) {
+    uint8_t ihash[32];
+    blake224_final(&S->inner, ihash);
+    blake224_update(&S->outer, ihash, 224);
+    blake224_final(&S->outer, digest);
+    memset(ihash, 0, 32);
+}
+
+// keylen = number of bytes; inlen = number of bytes
+void hmac_blake256_hash(uint8_t *out, const uint8_t *key, uint64_t keylen, const uint8_t *in, uint64_t inlen) {
+    hmac_state S;
+    hmac_blake256_init(&S, key, keylen);
+    hmac_blake256_update(&S, in, inlen * 8);
+    hmac_blake256_final(&S, out);
+}
+
+// keylen = number of bytes; inlen = number of bytes
+void hmac_blake224_hash(uint8_t *out, const uint8_t *key, uint64_t keylen, const uint8_t *in, uint64_t inlen) {
+    hmac_state S;
+    hmac_blake224_init(&S, key, keylen);
+    hmac_blake224_update(&S, in, inlen * 8);
+    hmac_blake224_final(&S, out);
+}
diff --git a/crypt/monero_crypto/blake256.h b/crypt/monero_crypto/blake256.h
new file mode 100644
index 0000000000..921fcd2fd5
--- /dev/null
+++ b/crypt/monero_crypto/blake256.h
@@ -0,0 +1,73 @@
+// 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>
+
+typedef struct {
+  uint32_t h[8], s[4], t[2];
+  int buflen, nullt;
+  uint8_t buf[64];
+} state;
+
+typedef struct {
+  state inner;
+  state outer;
+} hmac_state;
+
+void blake256_init(state *);
+void blake224_init(state *);
+
+void blake256_update(state *, const uint8_t *, uint64_t);
+void blake224_update(state *, const uint8_t *, uint64_t);
+
+void blake256_final(state *, uint8_t *);
+void blake224_final(state *, uint8_t *);
+
+void blake256_hash(uint8_t *, const uint8_t *, uint64_t);
+void blake224_hash(uint8_t *, const uint8_t *, uint64_t);
+
+/* HMAC functions: */
+
+void hmac_blake256_init(hmac_state *, const uint8_t *, uint64_t);
+void hmac_blake224_init(hmac_state *, const uint8_t *, uint64_t);
+
+void hmac_blake256_update(hmac_state *, const uint8_t *, uint64_t);
+void hmac_blake224_update(hmac_state *, const uint8_t *, uint64_t);
+
+void hmac_blake256_final(hmac_state *, uint8_t *);
+void hmac_blake224_final(hmac_state *, uint8_t *);
+
+void hmac_blake256_hash(uint8_t *, const uint8_t *, uint64_t, const uint8_t *, uint64_t);
+void hmac_blake224_hash(uint8_t *, const uint8_t *, uint64_t, const uint8_t *, uint64_t);
+
+#endif /* _BLAKE256_H_ */
diff --git a/crypt/monero_crypto/chacha8.c b/crypt/monero_crypto/chacha8.c
new file mode 100644
index 0000000000..df135af594
--- /dev/null
+++ b/crypt/monero_crypto/chacha8.c
@@ -0,0 +1,170 @@
+/*
+chacha-merged.c version 20080118
+D. J. Bernstein
+Public domain.
+*/
+
+#include <memory.h>
+#include <stdio.h>
+#include <sys/param.h>
+
+#include "chacha8.h"
+#include "common/int-util.h"
+#include "warnings.h"
+
+/*
+ * The following macros are used to obtain exact-width results.
+ */
+#define U8V(v) ((uint8_t)(v) & UINT8_C(0xFF))
+#define U32V(v) ((uint32_t)(v) & UINT32_C(0xFFFFFFFF))
+
+/*
+ * The following macros load words from an array of bytes with
+ * different types of endianness, and vice versa.
+ */
+#define U8TO32_LITTLE(p) SWAP32LE(((uint32_t*)(p))[0])
+#define U32TO8_LITTLE(p, v) (((uint32_t*)(p))[0] = SWAP32LE(v))
+
+#define ROTATE(v,c) (rol32(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);
+
+static const char sigma[] = "expand 32-byte k";
+
+DISABLE_GCC_AND_CLANG_WARNING(strict-aliasing)
+
+void chacha8(const void* data, size_t length, const uint8_t* key, const uint8_t* iv, char* cipher) {
+  uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
+  uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
+  char* ctarget = 0;
+  char tmp[64];
+  int i;
+
+  if (!length) return;
+
+  j0  = U8TO32_LITTLE(sigma + 0);
+  j1  = U8TO32_LITTLE(sigma + 4);
+  j2  = U8TO32_LITTLE(sigma + 8);
+  j3  = U8TO32_LITTLE(sigma + 12);
+  j4  = U8TO32_LITTLE(key + 0);
+  j5  = U8TO32_LITTLE(key + 4);
+  j6  = U8TO32_LITTLE(key + 8);
+  j7  = U8TO32_LITTLE(key + 12);
+  j8  = U8TO32_LITTLE(key + 16);
+  j9  = U8TO32_LITTLE(key + 20);
+  j10 = U8TO32_LITTLE(key + 24);
+  j11 = U8TO32_LITTLE(key + 28);
+  j12 = 0;
+  j13 = 0;
+  j14 = U8TO32_LITTLE(iv + 0);
+  j15 = U8TO32_LITTLE(iv + 4);
+
+  for (;;) {
+    if (length < 64) {
+      memcpy(tmp, data, length);
+      data = tmp;
+      ctarget = cipher;
+      cipher = 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 = 8;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((uint8_t*)data +  0));
+    x1  = XOR( x1,U8TO32_LITTLE((uint8_t*)data +  4));
+    x2  = XOR( x2,U8TO32_LITTLE((uint8_t*)data +  8));
+    x3  = XOR( x3,U8TO32_LITTLE((uint8_t*)data + 12));
+    x4  = XOR( x4,U8TO32_LITTLE((uint8_t*)data + 16));
+    x5  = XOR( x5,U8TO32_LITTLE((uint8_t*)data + 20));
+    x6  = XOR( x6,U8TO32_LITTLE((uint8_t*)data + 24));
+    x7  = XOR( x7,U8TO32_LITTLE((uint8_t*)data + 28));
+    x8  = XOR( x8,U8TO32_LITTLE((uint8_t*)data + 32));
+    x9  = XOR( x9,U8TO32_LITTLE((uint8_t*)data + 36));
+    x10 = XOR(x10,U8TO32_LITTLE((uint8_t*)data + 40));
+    x11 = XOR(x11,U8TO32_LITTLE((uint8_t*)data + 44));
+    x12 = XOR(x12,U8TO32_LITTLE((uint8_t*)data + 48));
+    x13 = XOR(x13,U8TO32_LITTLE((uint8_t*)data + 52));
+    x14 = XOR(x14,U8TO32_LITTLE((uint8_t*)data + 56));
+    x15 = XOR(x15,U8TO32_LITTLE((uint8_t*)data + 60));
+
+    j12 = PLUSONE(j12);
+    if (!j12)
+    {
+      j13 = PLUSONE(j13);
+      /* stopping at 2^70 bytes per iv is user's responsibility */
+    }
+
+    U32TO8_LITTLE(cipher +  0,x0);
+    U32TO8_LITTLE(cipher +  4,x1);
+    U32TO8_LITTLE(cipher +  8,x2);
+    U32TO8_LITTLE(cipher + 12,x3);
+    U32TO8_LITTLE(cipher + 16,x4);
+    U32TO8_LITTLE(cipher + 20,x5);
+    U32TO8_LITTLE(cipher + 24,x6);
+    U32TO8_LITTLE(cipher + 28,x7);
+    U32TO8_LITTLE(cipher + 32,x8);
+    U32TO8_LITTLE(cipher + 36,x9);
+    U32TO8_LITTLE(cipher + 40,x10);
+    U32TO8_LITTLE(cipher + 44,x11);
+    U32TO8_LITTLE(cipher + 48,x12);
+    U32TO8_LITTLE(cipher + 52,x13);
+    U32TO8_LITTLE(cipher + 56,x14);
+    U32TO8_LITTLE(cipher + 60,x15);
+
+    if (length <= 64) {
+      if (length < 64) {
+        memcpy(ctarget, cipher, length);
+      }
+      return;
+    }
+    length -= 64;
+    cipher += 64;
+    data = (uint8_t*)data + 64;
+  }
+}
diff --git a/crypt/monero_crypto/chacha8.h b/crypt/monero_crypto/chacha8.h
new file mode 100644
index 0000000000..dcbe6a933a
--- /dev/null
+++ b/crypt/monero_crypto/chacha8.h
@@ -0,0 +1,79 @@
+// 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
+
+#pragma once
+
+#include <stdint.h>
+#include <stddef.h>
+
+#define CHACHA8_KEY_SIZE 32
+#define CHACHA8_IV_SIZE 8
+
+#if defined(__cplusplus)
+#include <memory.h>
+
+#include "common/memwipe.h"
+#include "hash.h"
+
+namespace crypto {
+  extern "C" {
+#endif
+    void chacha8(const void* data, size_t length, const uint8_t* key, const uint8_t* iv, char* cipher);
+#if defined(__cplusplus)
+  }
+
+  using chacha8_key = tools::scrubbed_arr<uint8_t, CHACHA8_KEY_SIZE>;
+
+#pragma pack(push, 1)
+  // MS VC 2012 doesn't interpret `class chacha8_iv` as POD in spite of [9.0.10], so it is a struct
+  struct chacha8_iv {
+    uint8_t data[CHACHA8_IV_SIZE];
+  };
+#pragma pack(pop)
+
+  static_assert(sizeof(chacha8_key) == CHACHA8_KEY_SIZE && sizeof(chacha8_iv) == CHACHA8_IV_SIZE, "Invalid structure size");
+
+  inline void chacha8(const void* data, std::size_t length, const chacha8_key& key, const chacha8_iv& iv, char* cipher) {
+    chacha8(data, length, key.data(), reinterpret_cast<const uint8_t*>(&iv), cipher);
+  }
+
+  inline void generate_chacha8_key(const void *data, size_t size, chacha8_key& key) {
+    static_assert(sizeof(chacha8_key) <= sizeof(hash), "Size of hash must be at least that of chacha8_key");
+    tools::scrubbed_arr<char, HASH_SIZE> pwd_hash;
+    crypto::cn_slow_hash(data, size, pwd_hash.data());
+    memcpy(&key, pwd_hash.data(), sizeof(key));
+  }
+
+  inline void generate_chacha8_key(std::string password, chacha8_key& key) {
+    return generate_chacha8_key(password.data(), password.size(), key);
+  }
+}
+
+#endif
diff --git a/crypt/monero_crypto/crypto-ops-data.c b/crypt/monero_crypto/crypto-ops-data.c
new file mode 100644
index 0000000000..4bd75b77c6
--- /dev/null
+++ b/crypt/monero_crypto/crypto-ops-data.c
@@ -0,0 +1,872 @@
+// 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
+
+#include <stdint.h>
+
+#include "crypto-ops.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 */
+const fe fe_d = {-10913610, 13857413, -15372611, 6949391, 114729, -8787816, -6275908, -3247719, -18696448, -12055116}; /* d */
+const fe fe_sqrtm1 = {-32595792, -7943725, 9377950, 3500415, 12389472, -272473, -25146209, -2005654, 326686, 11406482}; /* sqrt(-1) */
+const fe fe_d2 = {-21827239, -5839606, -30745221, 13898782, 229458, 15978800, -12551817, -6495438, 29715968, 9444199}; /* 2 * d */
+
+/* base[i][j] = (j+1)*256^i*B */
+const ge_precomp ge_base[32][8] = {
+  {
+    {{25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605},
+     {-12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378},
+     {-8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546}},
+    {{-12815894, -12976347, -21581243, 11784320, -25355658, -2750717, -11717903, -3814571, -358445, -10211303},
+     {-21703237, 6903825, 27185491, 6451973, -29577724, -9554005, -15616551, 11189268, -26829678, -5319081},
+     {26966642, 11152617, 32442495, 15396054, 14353839, -12752335, -3128826, -9541118, -15472047, -4166697}},
+    {{15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024},
+     {16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574},
+     {30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357}},
+    {{-17036878, 13921892, 10945806, -6033431, 27105052, -16084379, -28926210, 15006023, 3284568, -6276540},
+     {23599295, -8306047, -11193664, -7687416, 13236774, 10506355, 7464579, 9656445, 13059162, 10374397},
+     {7798556, 16710257, 3033922, 2874086, 28997861, 2835604, 32406664, -3839045, -641708, -101325}},
+    {{10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380},
+     {4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306},
+     {19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942}},
+    {{-15371964, -12862754, 32573250, 4720197, -26436522, 5875511, -19188627, -15224819, -9818940, -12085777},
+     {-8549212, 109983, 15149363, 2178705, 22900618, 4543417, 3044240, -15689887, 1762328, 14866737},
+     {-18199695, -15951423, -10473290, 1707278, -17185920, 3916101, -28236412, 3959421, 27914454, 4383652}},
+    {{5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766},
+     {-30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701},
+     {28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300}},
+    {{14499471, -2729599, -33191113, -4254652, 28494862, 14271267, 30290735, 10876454, -33154098, 2381726},
+     {-7195431, -2655363, -14730155, 462251, -27724326, 3941372, -6236617, 3696005, -32300832, 15351955},
+     {27431194, 8222322, 16448760, -3907995, -18707002, 11938355, -32961401, -2970515, 29551813, 10109425}}
+  }, {
+    {{-13657040, -13155431, -31283750, 11777098, 21447386, 6519384, -2378284, -1627556, 10092783, -4764171},
+     {27939166, 14210322, 4677035, 16277044, -22964462, -12398139, -32508754, 12005538, -17810127, 12803510},
+     {17228999, -15661624, -1233527, 300140, -1224870, -11714777, 30364213, -9038194, 18016357, 4397660}},
+    {{-10958843, -7690207, 4776341, -14954238, 27850028, -15602212, -26619106, 14544525, -17477504, 982639},
+     {29253598, 15796703, -2863982, -9908884, 10057023, 3163536, 7332899, -4120128, -21047696, 9934963},
+     {5793303, 16271923, -24131614, -10116404, 29188560, 1206517, -14747930, 4559895, -30123922, -10897950}},
+    {{-27643952, -11493006, 16282657, -11036493, 28414021, -15012264, 24191034, 4541697, -13338309, 5500568},
+     {12650548, -1497113, 9052871, 11355358, -17680037, -8400164, -17430592, 12264343, 10874051, 13524335},
+     {25556948, -3045990, 714651, 2510400, 23394682, -10415330, 33119038, 5080568, -22528059, 5376628}},
+    {{-26088264, -4011052, -17013699, -3537628, -6726793, 1920897, -22321305, -9447443, 4535768, 1569007},
+     {-2255422, 14606630, -21692440, -8039818, 28430649, 8775819, -30494562, 3044290, 31848280, 12543772},
+     {-22028579, 2943893, -31857513, 6777306, 13784462, -4292203, -27377195, -2062731, 7718482, 14474653}},
+    {{2385315, 2454213, -22631320, 46603, -4437935, -15680415, 656965, -7236665, 24316168, -5253567},
+     {13741529, 10911568, -33233417, -8603737, -20177830, -1033297, 33040651, -13424532, -20729456, 8321686},
+     {21060490, -2212744, 15712757, -4336099, 1639040, 10656336, 23845965, -11874838, -9984458, 608372}},
+    {{-13672732, -15087586, -10889693, -7557059, -6036909, 11305547, 1123968, -6780577, 27229399, 23887},
+     {-23244140, -294205, -11744728, 14712571, -29465699, -2029617, 12797024, -6440308, -1633405, 16678954},
+     {-29500620, 4770662, -16054387, 14001338, 7830047, 9564805, -1508144, -4795045, -17169265, 4904953}},
+    {{24059557, 14617003, 19037157, -15039908, 19766093, -14906429, 5169211, 16191880, 2128236, -4326833},
+     {-16981152, 4124966, -8540610, -10653797, 30336522, -14105247, -29806336, 916033, -6882542, -2986532},
+     {-22630907, 12419372, -7134229, -7473371, -16478904, 16739175, 285431, 2763829, 15736322, 4143876}},
+    {{2379352, 11839345, -4110402, -5988665, 11274298, 794957, 212801, -14594663, 23527084, -16458268},
+     {33431127, -11130478, -17838966, -15626900, 8909499, 8376530, -32625340, 4087881, -15188911, -14416214},
+     {1767683, 7197987, -13205226, -2022635, -13091350, 448826, 5799055, 4357868, -4774191, -16323038}}
+  }, {
+    {{6721966, 13833823, -23523388, -1551314, 26354293, -11863321, 23365147, -3949732, 7390890, 2759800},
+     {4409041, 2052381, 23373853, 10530217, 7676779, -12885954, 21302353, -4264057, 1244380, -12919645},
+     {-4421239, 7169619, 4982368, -2957590, 30256825, -2777540, 14086413, 9208236, 15886429, 16489664}},
+    {{1996075, 10375649, 14346367, 13311202, -6874135, -16438411, -13693198, 398369, -30606455, -712933},
+     {-25307465, 9795880, -2777414, 14878809, -33531835, 14780363, 13348553, 12076947, -30836462, 5113182},
+     {-17770784, 11797796, 31950843, 13929123, -25888302, 12288344, -30341101, -7336386, 13847711, 5387222}},
+    {{-18582163, -3416217, 17824843, -2340966, 22744343, -10442611, 8763061, 3617786, -19600662, 10370991},
+     {20246567, -14369378, 22358229, -543712, 18507283, -10413996, 14554437, -8746092, 32232924, 16763880},
+     {9648505, 10094563, 26416693, 14745928, -30374318, -6472621, 11094161, 15689506, 3140038, -16510092}},
+    {{-16160072, 5472695, 31895588, 4744994, 8823515, 10365685, -27224800, 9448613, -28774454, 366295},
+     {19153450, 11523972, -11096490, -6503142, -24647631, 5420647, 28344573, 8041113, 719605, 11671788},
+     {8678025, 2694440, -6808014, 2517372, 4964326, 11152271, -15432916, -15266516, 27000813, -10195553}},
+    {{-15157904, 7134312, 8639287, -2814877, -7235688, 10421742, 564065, 5336097, 6750977, -14521026},
+     {11836410, -3979488, 26297894, 16080799, 23455045, 15735944, 1695823, -8819122, 8169720, 16220347},
+     {-18115838, 8653647, 17578566, -6092619, -8025777, -16012763, -11144307, -2627664, -5990708, -14166033}},
+    {{-23308498, -10968312, 15213228, -10081214, -30853605, -11050004, 27884329, 2847284, 2655861, 1738395},
+     {-27537433, -14253021, -25336301, -8002780, -9370762, 8129821, 21651608, -3239336, -19087449, -11005278},
+     {1533110, 3437855, 23735889, 459276, 29970501, 11335377, 26030092, 5821408, 10478196, 8544890}},
+    {{32173121, -16129311, 24896207, 3921497, 22579056, -3410854, 19270449, 12217473, 17789017, -3395995},
+     {-30552961, -2228401, -15578829, -10147201, 13243889, 517024, 15479401, -3853233, 30460520, 1052596},
+     {-11614875, 13323618, 32618793, 8175907, -15230173, 12596687, 27491595, -4612359, 3179268, -9478891}},
+    {{31947069, -14366651, -4640583, -15339921, -15125977, -6039709, -14756777, -16411740, 19072640, -9511060},
+     {11685058, 11822410, 3158003, -13952594, 33402194, -4165066, 5977896, -5215017, 473099, 5040608},
+     {-20290863, 8198642, -27410132, 11602123, 1290375, -2799760, 28326862, 1721092, -19558642, -3131606}}
+  }, {
+    {{7881532, 10687937, 7578723, 7738378, -18951012, -2553952, 21820786, 8076149, -27868496, 11538389},
+     {-19935666, 3899861, 18283497, -6801568, -15728660, -11249211, 8754525, 7446702, -5676054, 5797016},
+     {-11295600, -3793569, -15782110, -7964573, 12708869, -8456199, 2014099, -9050574, -2369172, -5877341}},
+    {{-22472376, -11568741, -27682020, 1146375, 18956691, 16640559, 1192730, -3714199, 15123619, 10811505},
+     {14352098, -3419715, -18942044, 10822655, 32750596, 4699007, -70363, 15776356, -28886779, -11974553},
+     {-28241164, -8072475, -4978962, -5315317, 29416931, 1847569, -20654173, -16484855, 4714547, -9600655}},
+    {{15200332, 8368572, 19679101, 15970074, -31872674, 1959451, 24611599, -4543832, -11745876, 12340220},
+     {12876937, -10480056, 33134381, 6590940, -6307776, 14872440, 9613953, 8241152, 15370987, 9608631},
+     {-4143277, -12014408, 8446281, -391603, 4407738, 13629032, -7724868, 15866074, -28210621, -8814099}},
+    {{26660628, -15677655, 8393734, 358047, -7401291, 992988, -23904233, 858697, 20571223, 8420556},
+     {14620715, 13067227, -15447274, 8264467, 14106269, 15080814, 33531827, 12516406, -21574435, -12476749},
+     {236881, 10476226, 57258, -14677024, 6472998, 2466984, 17258519, 7256740, 8791136, 15069930}},
+    {{1276410, -9371918, 22949635, -16322807, -23493039, -5702186, 14711875, 4874229, -30663140, -2331391},
+     {5855666, 4990204, -13711848, 7294284, -7804282, 1924647, -1423175, -7912378, -33069337, 9234253},
+     {20590503, -9018988, 31529744, -7352666, -2706834, 10650548, 31559055, -11609587, 18979186, 13396066}},
+    {{24474287, 4968103, 22267082, 4407354, 24063882, -8325180, -18816887, 13594782, 33514650, 7021958},
+     {-11566906, -6565505, -21365085, 15928892, -26158305, 4315421, -25948728, -3916677, -21480480, 12868082},
+     {-28635013, 13504661, 19988037, -2132761, 21078225, 6443208, -21446107, 2244500, -12455797, -8089383}},
+    {{-30595528, 13793479, -5852820, 319136, -25723172, -6263899, 33086546, 8957937, -15233648, 5540521},
+     {-11630176, -11503902, -8119500, -7643073, 2620056, 1022908, -23710744, -1568984, -16128528, -14962807},
+     {23152971, 775386, 27395463, 14006635, -9701118, 4649512, 1689819, 892185, -11513277, -15205948}},
+    {{9770129, 9586738, 26496094, 4324120, 1556511, -3550024, 27453819, 4763127, -19179614, 5867134},
+     {-32765025, 1927590, 31726409, -4753295, 23962434, -16019500, 27846559, 5931263, -29749703, -16108455},
+     {27461885, -2977536, 22380810, 1815854, -23033753, -3031938, 7283490, -15148073, -19526700, 7734629}}
+  }, {
+    {{-8010264, -9590817, -11120403, 6196038, 29344158, -13430885, 7585295, -3176626, 18549497, 15302069},
+     {-32658337, -6171222, -7672793, -11051681, 6258878, 13504381, 10458790, -6418461, -8872242, 8424746},
+     {24687205, 8613276, -30667046, -3233545, 1863892, -1830544, 19206234, 7134917, -11284482, -828919}},
+    {{11334899, -9218022, 8025293, 12707519, 17523892, -10476071, 10243738, -14685461, -5066034, 16498837},
+     {8911542, 6887158, -9584260, -6958590, 11145641, -9543680, 17303925, -14124238, 6536641, 10543906},
+     {-28946384, 15479763, -17466835, 568876, -1497683, 11223454, -2669190, -16625574, -27235709, 8876771}},
+    {{-25742899, -12566864, -15649966, -846607, -33026686, -796288, -33481822, 15824474, -604426, -9039817},
+     {10330056, 70051, 7957388, -9002667, 9764902, 15609756, 27698697, -4890037, 1657394, 3084098},
+     {10477963, -7470260, 12119566, -13250805, 29016247, -5365589, 31280319, 14396151, -30233575, 15272409}},
+    {{-12288309, 3169463, 28813183, 16658753, 25116432, -5630466, -25173957, -12636138, -25014757, 1950504},
+     {-26180358, 9489187, 11053416, -14746161, -31053720, 5825630, -8384306, -8767532, 15341279, 8373727},
+     {28685821, 7759505, -14378516, -12002860, -31971820, 4079242, 298136, -10232602, -2878207, 15190420}},
+    {{-32932876, 13806336, -14337485, -15794431, -24004620, 10940928, 8669718, 2742393, -26033313, -6875003},
+     {-1580388, -11729417, -25979658, -11445023, -17411874, -10912854, 9291594, -16247779, -12154742, 6048605},
+     {-30305315, 14843444, 1539301, 11864366, 20201677, 1900163, 13934231, 5128323, 11213262, 9168384}},
+    {{-26280513, 11007847, 19408960, -940758, -18592965, -4328580, -5088060, -11105150, 20470157, -16398701},
+     {-23136053, 9282192, 14855179, -15390078, -7362815, -14408560, -22783952, 14461608, 14042978, 5230683},
+     {29969567, -2741594, -16711867, -8552442, 9175486, -2468974, 21556951, 3506042, -5933891, -12449708}},
+    {{-3144746, 8744661, 19704003, 4581278, -20430686, 6830683, -21284170, 8971513, -28539189, 15326563},
+     {-19464629, 10110288, -17262528, -3503892, -23500387, 1355669, -15523050, 15300988, -20514118, 9168260},
+     {-5353335, 4488613, -23803248, 16314347, 7780487, -15638939, -28948358, 9601605, 33087103, -9011387}},
+    {{-19443170, -15512900, -20797467, -12445323, -29824447, 10229461, -27444329, -15000531, -5996870, 15664672},
+     {23294591, -16632613, -22650781, -8470978, 27844204, 11461195, 13099750, -2460356, 18151676, 13417686},
+     {-24722913, -4176517, -31150679, 5988919, -26858785, 6685065, 1661597, -12551441, 15271676, -15452665}}
+  }, {
+    {{11433042, -13228665, 8239631, -5279517, -1985436, -725718, -18698764, 2167544, -6921301, -13440182},
+     {-31436171, 15575146, 30436815, 12192228, -22463353, 9395379, -9917708, -8638997, 12215110, 12028277},
+     {14098400, 6555944, 23007258, 5757252, -15427832, -12950502, 30123440, 4617780, -16900089, -655628}},
+    {{-4026201, -15240835, 11893168, 13718664, -14809462, 1847385, -15819999, 10154009, 23973261, -12684474},
+     {-26531820, -3695990, -1908898, 2534301, -31870557, -16550355, 18341390, -11419951, 32013174, -10103539},
+     {-25479301, 10876443, -11771086, -14625140, -12369567, 1838104, 21911214, 6354752, 4425632, -837822}},
+    {{-10433389, -14612966, 22229858, -3091047, -13191166, 776729, -17415375, -12020462, 4725005, 14044970},
+     {19268650, -7304421, 1555349, 8692754, -21474059, -9910664, 6347390, -1411784, -19522291, -16109756},
+     {-24864089, 12986008, -10898878, -5558584, -11312371, -148526, 19541418, 8180106, 9282262, 10282508}},
+    {{-26205082, 4428547, -8661196, -13194263, 4098402, -14165257, 15522535, 8372215, 5542595, -10702683},
+     {-10562541, 14895633, 26814552, -16673850, -17480754, -2489360, -2781891, 6993761, -18093885, 10114655},
+     {-20107055, -929418, 31422704, 10427861, -7110749, 6150669, -29091755, -11529146, 25953725, -106158}},
+    {{-4234397, -8039292, -9119125, 3046000, 2101609, -12607294, 19390020, 6094296, -3315279, 12831125},
+     {-15998678, 7578152, 5310217, 14408357, -33548620, -224739, 31575954, 6326196, 7381791, -2421839},
+     {-20902779, 3296811, 24736065, -16328389, 18374254, 7318640, 6295303, 8082724, -15362489, 12339664}},
+    {{27724736, 2291157, 6088201, -14184798, 1792727, 5857634, 13848414, 15768922, 25091167, 14856294},
+     {-18866652, 8331043, 24373479, 8541013, -701998, -9269457, 12927300, -12695493, -22182473, -9012899},
+     {-11423429, -5421590, 11632845, 3405020, 30536730, -11674039, -27260765, 13866390, 30146206, 9142070}},
+    {{3924129, -15307516, -13817122, -10054960, 12291820, -668366, -27702774, 9326384, -8237858, 4171294},
+     {-15921940, 16037937, 6713787, 16606682, -21612135, 2790944, 26396185, 3731949, 345228, -5462949},
+     {-21327538, 13448259, 25284571, 1143661, 20614966, -8849387, 2031539, -12391231, -16253183, -13582083}},
+    {{31016211, -16722429, 26371392, -14451233, -5027349, 14854137, 17477601, 3842657, 28012650, -16405420},
+     {-5075835, 9368966, -8562079, -4600902, -15249953, 6970560, -9189873, 16292057, -8867157, 3507940},
+     {29439664, 3537914, 23333589, 6997794, -17555561, -11018068, -15209202, -15051267, -9164929, 6580396}}
+  }, {
+    {{-12185861, -7679788, 16438269, 10826160, -8696817, -6235611, 17860444, -9273846, -2095802, 9304567},
+     {20714564, -4336911, 29088195, 7406487, 11426967, -5095705, 14792667, -14608617, 5289421, -477127},
+     {-16665533, -10650790, -6160345, -13305760, 9192020, -1802462, 17271490, 12349094, 26939669, -3752294}},
+    {{-12889898, 9373458, 31595848, 16374215, 21471720, 13221525, -27283495, -12348559, -3698806, 117887},
+     {22263325, -6560050, 3984570, -11174646, -15114008, -566785, 28311253, 5358056, -23319780, 541964},
+     {16259219, 3261970, 2309254, -15534474, -16885711, -4581916, 24134070, -16705829, -13337066, -13552195}},
+    {{9378160, -13140186, -22845982, -12745264, 28198281, -7244098, -2399684, -717351, 690426, 14876244},
+     {24977353, -314384, -8223969, -13465086, 28432343, -1176353, -13068804, -12297348, -22380984, 6618999},
+     {-1538174, 11685646, 12944378, 13682314, -24389511, -14413193, 8044829, -13817328, 32239829, -5652762}},
+    {{-18603066, 4762990, -926250, 8885304, -28412480, -3187315, 9781647, -10350059, 32779359, 5095274},
+     {-33008130, -5214506, -32264887, -3685216, 9460461, -9327423, -24601656, 14506724, 21639561, -2630236},
+     {-16400943, -13112215, 25239338, 15531969, 3987758, -4499318, -1289502, -6863535, 17874574, 558605}},
+    {{-13600129, 10240081, 9171883, 16131053, -20869254, 9599700, 33499487, 5080151, 2085892, 5119761},
+     {-22205145, -2519528, -16381601, 414691, -25019550, 2170430, 30634760, -8363614, -31999993, -5759884},
+     {-6845704, 15791202, 8550074, -1312654, 29928809, -12092256, 27534430, -7192145, -22351378, 12961482}},
+    {{-24492060, -9570771, 10368194, 11582341, -23397293, -2245287, 16533930, 8206996, -30194652, -5159638},
+     {-11121496, -3382234, 2307366, 6362031, -135455, 8868177, -16835630, 7031275, 7589640, 8945490},
+     {-32152748, 8917967, 6661220, -11677616, -1192060, -15793393, 7251489, -11182180, 24099109, -14456170}},
+    {{5019558, -7907470, 4244127, -14714356, -26933272, 6453165, -19118182, -13289025, -6231896, -10280736},
+     {10853594, 10721687, 26480089, 5861829, -22995819, 1972175, -1866647, -10557898, -3363451, -6441124},
+     {-17002408, 5906790, 221599, -6563147, 7828208, -13248918, 24362661, -2008168, -13866408, 7421392}},
+    {{8139927, -6546497, 32257646, -5890546, 30375719, 1886181, -21175108, 15441252, 28826358, -4123029},
+     {6267086, 9695052, 7709135, -16603597, -32869068, -1886135, 14795160, -7840124, 13746021, -1742048},
+     {28584902, 7787108, -6732942, -15050729, 22846041, -7571236, -3181936, -363524, 4771362, -8419958}}
+  }, {
+    {{24949256, 6376279, -27466481, -8174608, -18646154, -9930606, 33543569, -12141695, 3569627, 11342593},
+     {26514989, 4740088, 27912651, 3697550, 19331575, -11472339, 6809886, 4608608, 7325975, -14801071},
+     {-11618399, -14554430, -24321212, 7655128, -1369274, 5214312, -27400540, 10258390, -17646694, -8186692}},
+    {{11431204, 15823007, 26570245, 14329124, 18029990, 4796082, -31446179, 15580664, 9280358, -3973687},
+     {-160783, -10326257, -22855316, -4304997, -20861367, -13621002, -32810901, -11181622, -15545091, 4387441},
+     {-20799378, 12194512, 3937617, -5805892, -27154820, 9340370, -24513992, 8548137, 20617071, -7482001}},
+    {{-938825, -3930586, -8714311, 16124718, 24603125, -6225393, -13775352, -11875822, 24345683, 10325460},
+     {-19855277, -1568885, -22202708, 8714034, 14007766, 6928528, 16318175, -1010689, 4766743, 3552007},
+     {-21751364, -16730916, 1351763, -803421, -4009670, 3950935, 3217514, 14481909, 10988822, -3994762}},
+    {{15564307, -14311570, 3101243, 5684148, 30446780, -8051356, 12677127, -6505343, -8295852, 13296005},
+     {-9442290, 6624296, -30298964, -11913677, -4670981, -2057379, 31521204, 9614054, -30000824, 12074674},
+     {4771191, -135239, 14290749, -13089852, 27992298, 14998318, -1413936, -1556716, 29832613, -16391035}},
+    {{7064884, -7541174, -19161962, -5067537, -18891269, -2912736, 25825242, 5293297, -27122660, 13101590},
+     {-2298563, 2439670, -7466610, 1719965, -27267541, -16328445, 32512469, -5317593, -30356070, -4190957},
+     {-30006540, 10162316, -33180176, 3981723, -16482138, -13070044, 14413974, 9515896, 19568978, 9628812}},
+    {{33053803, 199357, 15894591, 1583059, 27380243, -4580435, -17838894, -6106839, -6291786, 3437740},
+     {-18978877, 3884493, 19469877, 12726490, 15913552, 13614290, -22961733, 70104, 7463304, 4176122},
+     {-27124001, 10659917, 11482427, -16070381, 12771467, -6635117, -32719404, -5322751, 24216882, 5944158}},
+    {{8894125, 7450974, -2664149, -9765752, -28080517, -12389115, 19345746, 14680796, 11632993, 5847885},
+     {26942781, -2315317, 9129564, -4906607, 26024105, 11769399, -11518837, 6367194, -9727230, 4782140},
+     {19916461, -4828410, -22910704, -11414391, 25606324, -5972441, 33253853, 8220911, 6358847, -1873857}},
+    {{801428, -2081702, 16569428, 11065167, 29875704, 96627, 7908388, -4480480, -13538503, 1387155},
+     {19646058, 5720633, -11416706, 12814209, 11607948, 12749789, 14147075, 15156355, -21866831, 11835260},
+     {19299512, 1155910, 28703737, 14890794, 2925026, 7269399, 26121523, 15467869, -26560550, 5052483}}
+  }, {
+    {{-3017432, 10058206, 1980837, 3964243, 22160966, 12322533, -6431123, -12618185, 12228557, -7003677},
+     {32944382, 14922211, -22844894, 5188528, 21913450, -8719943, 4001465, 13238564, -6114803, 8653815},
+     {22865569, -4652735, 27603668, -12545395, 14348958, 8234005, 24808405, 5719875, 28483275, 2841751}},
+    {{-16420968, -1113305, -327719, -12107856, 21886282, -15552774, -1887966, -315658, 19932058, -12739203},
+     {-11656086, 10087521, -8864888, -5536143, -19278573, -3055912, 3999228, 13239134, -4777469, -13910208},
+     {1382174, -11694719, 17266790, 9194690, -13324356, 9720081, 20403944, 11284705, -14013818, 3093230}},
+    {{16650921, -11037932, -1064178, 1570629, -8329746, 7352753, -302424, 16271225, -24049421, -6691850},
+     {-21911077, -5927941, -4611316, -5560156, -31744103, -10785293, 24123614, 15193618, -21652117, -16739389},
+     {-9935934, -4289447, -25279823, 4372842, 2087473, 10399484, 31870908, 14690798, 17361620, 11864968}},
+    {{-11307610, 6210372, 13206574, 5806320, -29017692, -13967200, -12331205, -7486601, -25578460, -16240689},
+     {14668462, -12270235, 26039039, 15305210, 25515617, 4542480, 10453892, 6577524, 9145645, -6443880},
+     {5974874, 3053895, -9433049, -10385191, -31865124, 3225009, -7972642, 3936128, -5652273, -3050304}},
+    {{30625386, -4729400, -25555961, -12792866, -20484575, 7695099, 17097188, -16303496, -27999779, 1803632},
+     {-3553091, 9865099, -5228566, 4272701, -5673832, -16689700, 14911344, 12196514, -21405489, 7047412},
+     {20093277, 9920966, -11138194, -5343857, 13161587, 12044805, -32856851, 4124601, -32343828, -10257566}},
+    {{-20788824, 14084654, -13531713, 7842147, 19119038, -13822605, 4752377, -8714640, -21679658, 2288038},
+     {-26819236, -3283715, 29965059, 3039786, -14473765, 2540457, 29457502, 14625692, -24819617, 12570232},
+     {-1063558, -11551823, 16920318, 12494842, 1278292, -5869109, -21159943, -3498680, -11974704, 4724943}},
+    {{17960970, -11775534, -4140968, -9702530, -8876562, -1410617, -12907383, -8659932, -29576300, 1903856},
+     {23134274, -14279132, -10681997, -1611936, 20684485, 15770816, -12989750, 3190296, 26955097, 14109738},
+     {15308788, 5320727, -30113809, -14318877, 22902008, 7767164, 29425325, -11277562, 31960942, 11934971}},
+    {{-27395711, 8435796, 4109644, 12222639, -24627868, 14818669, 20638173, 4875028, 10491392, 1379718},
+     {-13159415, 9197841, 3875503, -8936108, -1383712, -5879801, 33518459, 16176658, 21432314, 12180697},
+     {-11787308, 11500838, 13787581, -13832590, -22430679, 10140205, 1465425, 12689540, -10301319, -13872883}}
+  }, {
+    {{5414091, -15386041, -21007664, 9643570, 12834970, 1186149, -2622916, -1342231, 26128231, 6032912},
+     {-26337395, -13766162, 32496025, -13653919, 17847801, -12669156, 3604025, 8316894, -25875034, -10437358},
+     {3296484, 6223048, 24680646, -12246460, -23052020, 5903205, -8862297, -4639164, 12376617, 3188849}},
+    {{29190488, -14659046, 27549113, -1183516, 3520066, -10697301, 32049515, -7309113, -16109234, -9852307},
+     {-14744486, -9309156, 735818, -598978, -20407687, -5057904, 25246078, -15795669, 18640741, -960977},
+     {-6928835, -16430795, 10361374, 5642961, 4910474, 12345252, -31638386, -494430, 10530747, 1053335}},
+    {{-29265967, -14186805, -13538216, -12117373, -19457059, -10655384, -31462369, -2948985, 24018831, 15026644},
+     {-22592535, -3145277, -2289276, 5953843, -13440189, 9425631, 25310643, 13003497, -2314791, -15145616},
+     {-27419985, -603321, -8043984, -1669117, -26092265, 13987819, -27297622, 187899, -23166419, -2531735}},
+    {{-21744398, -13810475, 1844840, 5021428, -10434399, -15911473, 9716667, 16266922, -5070217, 726099},
+     {29370922, -6053998, 7334071, -15342259, 9385287, 2247707, -13661962, -4839461, 30007388, -15823341},
+     {-936379, 16086691, 23751945, -543318, -1167538, -5189036, 9137109, 730663, 9835848, 4555336}},
+    {{-23376435, 1410446, -22253753, -12899614, 30867635, 15826977, 17693930, 544696, -11985298, 12422646},
+     {31117226, -12215734, -13502838, 6561947, -9876867, -12757670, -5118685, -4096706, 29120153, 13924425},
+     {-17400879, -14233209, 19675799, -2734756, -11006962, -5858820, -9383939, -11317700, 7240931, -237388}},
+    {{-31361739, -11346780, -15007447, -5856218, -22453340, -12152771, 1222336, 4389483, 3293637, -15551743},
+     {-16684801, -14444245, 11038544, 11054958, -13801175, -3338533, -24319580, 7733547, 12796905, -6335822},
+     {-8759414, -10817836, -25418864, 10783769, -30615557, -9746811, -28253339, 3647836, 3222231, -11160462}},
+    {{18606113, 1693100, -25448386, -15170272, 4112353, 10045021, 23603893, -2048234, -7550776, 2484985},
+     {9255317, -3131197, -12156162, -1004256, 13098013, -9214866, 16377220, -2102812, -19802075, -3034702},
+     {-22729289, 7496160, -5742199, 11329249, 19991973, -3347502, -31718148, 9936966, -30097688, -10618797}},
+    {{21878590, -5001297, 4338336, 13643897, -3036865, 13160960, 19708896, 5415497, -7360503, -4109293},
+     {27736861, 10103576, 12500508, 8502413, -3413016, -9633558, 10436918, -1550276, -23659143, -8132100},
+     {19492550, -12104365, -29681976, -852630, -3208171, 12403437, 30066266, 8367329, 13243957, 8709688}}
+  }, {
+    {{12015105, 2801261, 28198131, 10151021, 24818120, -4743133, -11194191, -5645734, 5150968, 7274186},
+     {2831366, -12492146, 1478975, 6122054, 23825128, -12733586, 31097299, 6083058, 31021603, -9793610},
+     {-2529932, -2229646, 445613, 10720828, -13849527, -11505937, -23507731, 16354465, 15067285, -14147707}},
+    {{7840942, 14037873, -33364863, 15934016, -728213, -3642706, 21403988, 1057586, -19379462, -12403220},
+     {915865, -16469274, 15608285, -8789130, -24357026, 6060030, -17371319, 8410997, -7220461, 16527025},
+     {32922597, -556987, 20336074, -16184568, 10903705, -5384487, 16957574, 52992, 23834301, 6588044}},
+    {{32752030, 11232950, 3381995, -8714866, 22652988, -10744103, 17159699, 16689107, -20314580, -1305992},
+     {-4689649, 9166776, -25710296, -10847306, 11576752, 12733943, 7924251, -2752281, 1976123, -7249027},
+     {21251222, 16309901, -2983015, -6783122, 30810597, 12967303, 156041, -3371252, 12331345, -8237197}},
+    {{8651614, -4477032, -16085636, -4996994, 13002507, 2950805, 29054427, -5106970, 10008136, -4667901},
+     {31486080, 15114593, -14261250, 12951354, 14369431, -7387845, 16347321, -13662089, 8684155, -10532952},
+     {19443825, 11385320, 24468943, -9659068, -23919258, 2187569, -26263207, -6086921, 31316348, 14219878}},
+    {{-28594490, 1193785, 32245219, 11392485, 31092169, 15722801, 27146014, 6992409, 29126555, 9207390},
+     {32382935, 1110093, 18477781, 11028262, -27411763, -7548111, -4980517, 10843782, -7957600, -14435730},
+     {2814918, 7836403, 27519878, -7868156, -20894015, -11553689, -21494559, 8550130, 28346258, 1994730}},
+    {{-19578299, 8085545, -14000519, -3948622, 2785838, -16231307, -19516951, 7174894, 22628102, 8115180},
+     {-30405132, 955511, -11133838, -15078069, -32447087, -13278079, -25651578, 3317160, -9943017, 930272},
+     {-15303681, -6833769, 28856490, 1357446, 23421993, 1057177, 24091212, -1388970, -22765376, -10650715}},
+    {{-22751231, -5303997, -12907607, -12768866, -15811511, -7797053, -14839018, -16554220, -1867018, 8398970},
+     {-31969310, 2106403, -4736360, 1362501, 12813763, 16200670, 22981545, -6291273, 18009408, -15772772},
+     {-17220923, -9545221, -27784654, 14166835, 29815394, 7444469, 29551787, -3727419, 19288549, 1325865}},
+    {{15100157, -15835752, -23923978, -1005098, -26450192, 15509408, 12376730, -3479146, 33166107, -8042750},
+     {20909231, 13023121, -9209752, 16251778, -5778415, -8094914, 12412151, 10018715, 2213263, -13878373},
+     {32529814, -11074689, 30361439, -16689753, -9135940, 1513226, 22922121, 6382134, -5766928, 8371348}}
+  }, {
+    {{9923462, 11271500, 12616794, 3544722, -29998368, -1721626, 12891687, -8193132, -26442943, 10486144},
+     {-22597207, -7012665, 8587003, -8257861, 4084309, -12970062, 361726, 2610596, -23921530, -11455195},
+     {5408411, -1136691, -4969122, 10561668, 24145918, 14240566, 31319731, -4235541, 19985175, -3436086}},
+    {{-13994457, 16616821, 14549246, 3341099, 32155958, 13648976, -17577068, 8849297, 65030, 8370684},
+     {-8320926, -12049626, 31204563, 5839400, -20627288, -1057277, -19442942, 6922164, 12743482, -9800518},
+     {-2361371, 12678785, 28815050, 4759974, -23893047, 4884717, 23783145, 11038569, 18800704, 255233}},
+    {{-5269658, -1773886, 13957886, 7990715, 23132995, 728773, 13393847, 9066957, 19258688, -14753793},
+     {-2936654, -10827535, -10432089, 14516793, -3640786, 4372541, -31934921, 2209390, -1524053, 2055794},
+     {580882, 16705327, 5468415, -2683018, -30926419, -14696000, -7203346, -8994389, -30021019, 7394435}},
+    {{23838809, 1822728, -15738443, 15242727, 8318092, -3733104, -21672180, -3492205, -4821741, 14799921},
+     {13345610, 9759151, 3371034, -16137791, 16353039, 8577942, 31129804, 13496856, -9056018, 7402518},
+     {2286874, -4435931, -20042458, -2008336, -13696227, 5038122, 11006906, -15760352, 8205061, 1607563}},
+    {{14414086, -8002132, 3331830, -3208217, 22249151, -5594188, 18364661, -2906958, 30019587, -9029278},
+     {-27688051, 1585953, -10775053, 931069, -29120221, -11002319, -14410829, 12029093, 9944378, 8024},
+     {4368715, -3709630, 29874200, -15022983, -20230386, -11410704, -16114594, -999085, -8142388, 5640030}},
+    {{10299610, 13746483, 11661824, 16234854, 7630238, 5998374, 9809887, -16694564, 15219798, -14327783},
+     {27425505, -5719081, 3055006, 10660664, 23458024, 595578, -15398605, -1173195, -18342183, 9742717},
+     {6744077, 2427284, 26042789, 2720740, -847906, 1118974, 32324614, 7406442, 12420155, 1994844}},
+    {{14012521, -5024720, -18384453, -9578469, -26485342, -3936439, -13033478, -10909803, 24319929, -6446333},
+     {16412690, -4507367, 10772641, 15929391, -17068788, -4658621, 10555945, -10484049, -30102368, -4739048},
+     {22397382, -7767684, -9293161, -12792868, 17166287, -9755136, -27333065, 6199366, 21880021, -12250760}},
+    {{-4283307, 5368523, -31117018, 8163389, -30323063, 3209128, 16557151, 8890729, 8840445, 4957760},
+     {-15447727, 709327, -6919446, -10870178, -29777922, 6522332, -21720181, 12130072, -14796503, 5005757},
+     {-2114751, -14308128, 23019042, 15765735, -25269683, 6002752, 10183197, -13239326, -16395286, -2176112}}
+  }, {
+    {{-19025756, 1632005, 13466291, -7995100, -23640451, 16573537, -32013908, -3057104, 22208662, 2000468},
+     {3065073, -1412761, -25598674, -361432, -17683065, -5703415, -8164212, 11248527, -3691214, -7414184},
+     {10379208, -6045554, 8877319, 1473647, -29291284, -12507580, 16690915, 2553332, -3132688, 16400289}},
+    {{15716668, 1254266, -18472690, 7446274, -8448918, 6344164, -22097271, -7285580, 26894937, 9132066},
+     {24158887, 12938817, 11085297, -8177598, -28063478, -4457083, -30576463, 64452, -6817084, -2692882},
+     {13488534, 7794716, 22236231, 5989356, 25426474, -12578208, 2350710, -3418511, -4688006, 2364226}},
+    {{16335052, 9132434, 25640582, 6678888, 1725628, 8517937, -11807024, -11697457, 15445875, -7798101},
+     {29004207, -7867081, 28661402, -640412, -12794003, -7943086, 31863255, -4135540, -278050, -15759279},
+     {-6122061, -14866665, -28614905, 14569919, -10857999, -3591829, 10343412, -6976290, -29828287, -10815811}},
+    {{27081650, 3463984, 14099042, -4517604, 1616303, -6205604, 29542636, 15372179, 17293797, 960709},
+     {20263915, 11434237, -5765435, 11236810, 13505955, -10857102, -16111345, 6493122, -19384511, 7639714},
+     {-2830798, -14839232, 25403038, -8215196, -8317012, -16173699, 18006287, -16043750, 29994677, -15808121}},
+    {{9769828, 5202651, -24157398, -13631392, -28051003, -11561624, -24613141, -13860782, -31184575, 709464},
+     {12286395, 13076066, -21775189, -1176622, -25003198, 4057652, -32018128, -8890874, 16102007, 13205847},
+     {13733362, 5599946, 10557076, 3195751, -5557991, 8536970, -25540170, 8525972, 10151379, 10394400}},
+    {{4024660, -16137551, 22436262, 12276534, -9099015, -2686099, 19698229, 11743039, -33302334, 8934414},
+     {-15879800, -4525240, -8580747, -2934061, 14634845, -698278, -9449077, 3137094, -11536886, 11721158},
+     {17555939, -5013938, 8268606, 2331751, -22738815, 9761013, 9319229, 8835153, -9205489, -1280045}},
+    {{-461409, -7830014, 20614118, 16688288, -7514766, -4807119, 22300304, 505429, 6108462, -6183415},
+     {-5070281, 12367917, -30663534, 3234473, 32617080, -8422642, 29880583, -13483331, -26898490, -7867459},
+     {-31975283, 5726539, 26934134, 10237677, -3173717, -605053, 24199304, 3795095, 7592688, -14992079}},
+    {{21594432, -14964228, 17466408, -4077222, 32537084, 2739898, 6407723, 12018833, -28256052, 4298412},
+     {-20650503, -11961496, -27236275, 570498, 3767144, -1717540, 13891942, -1569194, 13717174, 10805743},
+     {-14676630, -15644296, 15287174, 11927123, 24177847, -8175568, -796431, 14860609, -26938930, -5863836}}
+  }, {
+    {{12962541, 5311799, -10060768, 11658280, 18855286, -7954201, 13286263, -12808704, -4381056, 9882022},
+     {18512079, 11319350, -20123124, 15090309, 18818594, 5271736, -22727904, 3666879, -23967430, -3299429},
+     {-6789020, -3146043, 16192429, 13241070, 15898607, -14206114, -10084880, -6661110, -2403099, 5276065}},
+    {{30169808, -5317648, 26306206, -11750859, 27814964, 7069267, 7152851, 3684982, 1449224, 13082861},
+     {10342826, 3098505, 2119311, 193222, 25702612, 12233820, 23697382, 15056736, -21016438, -8202000},
+     {-33150110, 3261608, 22745853, 7948688, 19370557, -15177665, -26171976, 6482814, -10300080, -11060101}},
+    {{32869458, -5408545, 25609743, 15678670, -10687769, -15471071, 26112421, 2521008, -22664288, 6904815},
+     {29506923, 4457497, 3377935, -9796444, -30510046, 12935080, 1561737, 3841096, -29003639, -6657642},
+     {10340844, -6630377, -18656632, -2278430, 12621151, -13339055, 30878497, -11824370, -25584551, 5181966}},
+    {{25940115, -12658025, 17324188, -10307374, -8671468, 15029094, 24396252, -16450922, -2322852, -12388574},
+     {-21765684, 9916823, -1300409, 4079498, -1028346, 11909559, 1782390, 12641087, 20603771, -6561742},
+     {-18882287, -11673380, 24849422, 11501709, 13161720, -4768874, 1925523, 11914390, 4662781, 7820689}},
+    {{12241050, -425982, 8132691, 9393934, 32846760, -1599620, 29749456, 12172924, 16136752, 15264020},
+     {-10349955, -14680563, -8211979, 2330220, -17662549, -14545780, 10658213, 6671822, 19012087, 3772772},
+     {3753511, -3421066, 10617074, 2028709, 14841030, -6721664, 28718732, -15762884, 20527771, 12988982}},
+    {{-14822485, -5797269, -3707987, 12689773, -898983, -10914866, -24183046, -10564943, 3299665, -12424953},
+     {-16777703, -15253301, -9642417, 4978983, 3308785, 8755439, 6943197, 6461331, -25583147, 8991218},
+     {-17226263, 1816362, -1673288, -6086439, 31783888, -8175991, -32948145, 7417950, -30242287, 1507265}},
+    {{29692663, 6829891, -10498800, 4334896, 20945975, -11906496, -28887608, 8209391, 14606362, -10647073},
+     {-3481570, 8707081, 32188102, 5672294, 22096700, 1711240, -33020695, 9761487, 4170404, -2085325},
+     {-11587470, 14855945, -4127778, -1531857, -26649089, 15084046, 22186522, 16002000, -14276837, -8400798}},
+    {{-4811456, 13761029, -31703877, -2483919, -3312471, 7869047, -7113572, -9620092, 13240845, 10965870},
+     {-7742563, -8256762, -14768334, -13656260, -23232383, 12387166, 4498947, 14147411, 29514390, 4302863},
+     {-13413405, -12407859, 20757302, -13801832, 14785143, 8976368, -5061276, -2144373, 17846988, -13971927}}
+  }, {
+    {{-2244452, -754728, -4597030, -1066309, -6247172, 1455299, -21647728, -9214789, -5222701, 12650267},
+     {-9906797, -16070310, 21134160, 12198166, -27064575, 708126, 387813, 13770293, -19134326, 10958663},
+     {22470984, 12369526, 23446014, -5441109, -21520802, -9698723, -11772496, -11574455, -25083830, 4271862}},
+    {{-25169565, -10053642, -19909332, 15361595, -5984358, 2159192, 75375, -4278529, -32526221, 8469673},
+     {15854970, 4148314, -8893890, 7259002, 11666551, 13824734, -30531198, 2697372, 24154791, -9460943},
+     {15446137, -15806644, 29759747, 14019369, 30811221, -9610191, -31582008, 12840104, 24913809, 9815020}},
+    {{-4709286, -5614269, -31841498, -12288893, -14443537, 10799414, -9103676, 13438769, 18735128, 9466238},
+     {11933045, 9281483, 5081055, -5183824, -2628162, -4905629, -7727821, -10896103, -22728655, 16199064},
+     {14576810, 379472, -26786533, -8317236, -29426508, -10812974, -102766, 1876699, 30801119, 2164795}},
+    {{15995086, 3199873, 13672555, 13712240, -19378835, -4647646, -13081610, -15496269, -13492807, 1268052},
+     {-10290614, -3659039, -3286592, 10948818, 23037027, 3794475, -3470338, -12600221, -17055369, 3565904},
+     {29210088, -9419337, -5919792, -4952785, 10834811, -13327726, -16512102, -10820713, -27162222, -14030531}},
+    {{-13161890, 15508588, 16663704, -8156150, -28349942, 9019123, -29183421, -3769423, 2244111, -14001979},
+     {-5152875, -3800936, -9306475, -6071583, 16243069, 14684434, -25673088, -16180800, 13491506, 4641841},
+     {10813417, 643330, -19188515, -728916, 30292062, -16600078, 27548447, -7721242, 14476989, -12767431}},
+    {{10292079, 9984945, 6481436, 8279905, -7251514, 7032743, 27282937, -1644259, -27912810, 12651324},
+     {-31185513, -813383, 22271204, 11835308, 10201545, 15351028, 17099662, 3988035, 21721536, -3148940},
+     {10202177, -6545839, -31373232, -9574638, -32150642, -8119683, -12906320, 3852694, 13216206, 14842320}},
+    {{-15815640, -10601066, -6538952, -7258995, -6984659, -6581778, -31500847, 13765824, -27434397, 9900184},
+     {14465505, -13833331, -32133984, -14738873, -27443187, 12990492, 33046193, 15796406, -7051866, -8040114},
+     {30924417, -8279620, 6359016, -12816335, 16508377, 9071735, -25488601, 15413635, 9524356, -7018878}},
+    {{12274201, -13175547, 32627641, -1785326, 6736625, 13267305, 5237659, -5109483, 15663516, 4035784},
+     {-2951309, 8903985, 17349946, 601635, -16432815, -4612556, -13732739, -15889334, -22258478, 4659091},
+     {-16916263, -4952973, -30393711, -15158821, 20774812, 15897498, 5736189, 15026997, -2178256, -13455585}}
+  }, {
+    {{-8858980, -2219056, 28571666, -10155518, -474467, -10105698, -3801496, 278095, 23440562, -290208},
+     {10226241, -5928702, 15139956, 120818, -14867693, 5218603, 32937275, 11551483, -16571960, -7442864},
+     {17932739, -12437276, -24039557, 10749060, 11316803, 7535897, 22503767, 5561594, -3646624, 3898661}},
+    {{7749907, -969567, -16339731, -16464, -25018111, 15122143, -1573531, 7152530, 21831162, 1245233},
+     {26958459, -14658026, 4314586, 8346991, -5677764, 11960072, -32589295, -620035, -30402091, -16716212},
+     {-12165896, 9166947, 33491384, 13673479, 29787085, 13096535, 6280834, 14587357, -22338025, 13987525}},
+    {{-24349909, 7778775, 21116000, 15572597, -4833266, -5357778, -4300898, -5124639, -7469781, -2858068},
+     {9681908, -6737123, -31951644, 13591838, -6883821, 386950, 31622781, 6439245, -14581012, 4091397},
+     {-8426427, 1470727, -28109679, -1596990, 3978627, -5123623, -19622683, 12092163, 29077877, -14741988}},
+    {{5269168, -6859726, -13230211, -8020715, 25932563, 1763552, -5606110, -5505881, -20017847, 2357889},
+     {32264008, -15407652, -5387735, -1160093, -2091322, -3946900, 23104804, -12869908, 5727338, 189038},
+     {14609123, -8954470, -6000566, -16622781, -14577387, -7743898, -26745169, 10942115, -25888931, -14884697}},
+    {{20513500, 5557931, -15604613, 7829531, 26413943, -2019404, -21378968, 7471781, 13913677, -5137875},
+     {-25574376, 11967826, 29233242, 12948236, -6754465, 4713227, -8940970, 14059180, 12878652, 8511905},
+     {-25656801, 3393631, -2955415, -7075526, -2250709, 9366908, -30223418, 6812974, 5568676, -3127656}},
+    {{11630004, 12144454, 2116339, 13606037, 27378885, 15676917, -17408753, -13504373, -14395196, 8070818},
+     {27117696, -10007378, -31282771, -5570088, 1127282, 12772488, -29845906, 10483306, -11552749, -1028714},
+     {10637467, -5688064, 5674781, 1072708, -26343588, -6982302, -1683975, 9177853, -27493162, 15431203}},
+    {{20525145, 10892566, -12742472, 12779443, -29493034, 16150075, -28240519, 14943142, -15056790, -7935931},
+     {-30024462, 5626926, -551567, -9981087, 753598, 11981191, 25244767, -3239766, -3356550, 9594024},
+     {-23752644, 2636870, -5163910, -10103818, 585134, 7877383, 11345683, -6492290, 13352335, -10977084}},
+    {{-1931799, -5407458, 3304649, -12884869, 17015806, -4877091, -29783850, -7752482, -13215537, -319204},
+     {20239939, 6607058, 6203985, 3483793, -18386976, -779229, -20723742, 15077870, -22750759, 14523817},
+     {27406042, -6041657, 27423596, -4497394, 4996214, 10002360, -28842031, -4545494, -30172742, -4805667}}
+  }, {
+    {{11374242, 12660715, 17861383, -12540833, 10935568, 1099227, -13886076, -9091740, -27727044, 11358504},
+     {-12730809, 10311867, 1510375, 10778093, -2119455, -9145702, 32676003, 11149336, -26123651, 4985768},
+     {-19096303, 341147, -6197485, -239033, 15756973, -8796662, -983043, 13794114, -19414307, -15621255}},
+    {{6490081, 11940286, 25495923, -7726360, 8668373, -8751316, 3367603, 6970005, -1691065, -9004790},
+     {1656497, 13457317, 15370807, 6364910, 13605745, 8362338, -19174622, -5475723, -16796596, -5031438},
+     {-22273315, -13524424, -64685, -4334223, -18605636, -10921968, -20571065, -7007978, -99853, -10237333}},
+    {{17747465, 10039260, 19368299, -4050591, -20630635, -16041286, 31992683, -15857976, -29260363, -5511971},
+     {31932027, -4986141, -19612382, 16366580, 22023614, 88450, 11371999, -3744247, 4882242, -10626905},
+     {29796507, 37186, 19818052, 10115756, -11829032, 3352736, 18551198, 3272828, -5190932, -4162409}},
+    {{12501286, 4044383, -8612957, -13392385, -32430052, 5136599, -19230378, -3529697, 330070, -3659409},
+     {6384877, 2899513, 17807477, 7663917, -2358888, 12363165, 25366522, -8573892, -271295, 12071499},
+     {-8365515, -4042521, 25133448, -4517355, -6211027, 2265927, -32769618, 1936675, -5159697, 3829363}},
+    {{28425966, -5835433, -577090, -4697198, -14217555, 6870930, 7921550, -6567787, 26333140, 14267664},
+     {-11067219, 11871231, 27385719, -10559544, -4585914, -11189312, 10004786, -8709488, -21761224, 8930324},
+     {-21197785, -16396035, 25654216, -1725397, 12282012, 11008919, 1541940, 4757911, -26491501, -16408940}},
+    {{13537262, -7759490, -20604840, 10961927, -5922820, -13218065, -13156584, 6217254, -15943699, 13814990},
+     {-17422573, 15157790, 18705543, 29619, 24409717, -260476, 27361681, 9257833, -1956526, -1776914},
+     {-25045300, -10191966, 15366585, 15166509, -13105086, 8423556, -29171540, 12361135, -18685978, 4578290}},
+    {{24579768, 3711570, 1342322, -11180126, -27005135, 14124956, -22544529, 14074919, 21964432, 8235257},
+     {-6528613, -2411497, 9442966, -5925588, 12025640, -1487420, -2981514, -1669206, 13006806, 2355433},
+     {-16304899, -13605259, -6632427, -5142349, 16974359, -10911083, 27202044, 1719366, 1141648, -12796236}},
+    {{-12863944, -13219986, -8318266, -11018091, -6810145, -4843894, 13475066, -3133972, 32674895, 13715045},
+     {11423335, -5468059, 32344216, 8962751, 24989809, 9241752, -13265253, 16086212, -28740881, -15642093},
+     {-1409668, 12530728, -6368726, 10847387, 19531186, -14132160, -11709148, 7791794, -27245943, 4383347}}
+  }, {
+    {{-28970898, 5271447, -1266009, -9736989, -12455236, 16732599, -4862407, -4906449, 27193557, 6245191},
+     {-15193956, 5362278, -1783893, 2695834, 4960227, 12840725, 23061898, 3260492, 22510453, 8577507},
+     {-12632451, 11257346, -32692994, 13548177, -721004, 10879011, 31168030, 13952092, -29571492, -3635906}},
+    {{3877321, -9572739, 32416692, 5405324, -11004407, -13656635, 3759769, 11935320, 5611860, 8164018},
+     {-16275802, 14667797, 15906460, 12155291, -22111149, -9039718, 32003002, -8832289, 5773085, -8422109},
+     {-23788118, -8254300, 1950875, 8937633, 18686727, 16459170, -905725, 12376320, 31632953, 190926}},
+    {{-24593607, -16138885, -8423991, 13378746, 14162407, 6901328, -8288749, 4508564, -25341555, -3627528},
+     {8884438, -5884009, 6023974, 10104341, -6881569, -4941533, 18722941, -14786005, -1672488, 827625},
+     {-32720583, -16289296, -32503547, 7101210, 13354605, 2659080, -1800575, -14108036, -24878478, 1541286}},
+    {{2901347, -1117687, 3880376, -10059388, -17620940, -3612781, -21802117, -3567481, 20456845, -1885033},
+     {27019610, 12299467, -13658288, -1603234, -12861660, -4861471, -19540150, -5016058, 29439641, 15138866},
+     {21536104, -6626420, -32447818, -10690208, -22408077, 5175814, -5420040, -16361163, 7779328, 109896}},
+    {{30279744, 14648750, -8044871, 6425558, 13639621, -743509, 28698390, 12180118, 23177719, -554075},
+     {26572847, 3405927, -31701700, 12890905, -19265668, 5335866, -6493768, 2378492, 4439158, -13279347},
+     {-22716706, 3489070, -9225266, -332753, 18875722, -1140095, 14819434, -12731527, -17717757, -5461437}},
+    {{-5056483, 16566551, 15953661, 3767752, -10436499, 15627060, -820954, 2177225, 8550082, -15114165},
+     {-18473302, 16596775, -381660, 15663611, 22860960, 15585581, -27844109, -3582739, -23260460, -8428588},
+     {-32480551, 15707275, -8205912, -5652081, 29464558, 2713815, -22725137, 15860482, -21902570, 1494193}},
+    {{-19562091, -14087393, -25583872, -9299552, 13127842, 759709, 21923482, 16529112, 8742704, 12967017},
+     {-28464899, 1553205, 32536856, -10473729, -24691605, -406174, -8914625, -2933896, -29903758, 15553883},
+     {21877909, 3230008, 9881174, 10539357, -4797115, 2841332, 11543572, 14513274, 19375923, -12647961}},
+    {{8832269, -14495485, 13253511, 5137575, 5037871, 4078777, 24880818, -6222716, 2862653, 9455043},
+     {29306751, 5123106, 20245049, -14149889, 9592566, 8447059, -2077124, -2990080, 15511449, 4789663},
+     {-20679756, 7004547, 8824831, -9434977, -4045704, -3750736, -5754762, 108893, 23513200, 16652362}}
+  }, {
+    {{-33256173, 4144782, -4476029, -6579123, 10770039, -7155542, -6650416, -12936300, -18319198, 10212860},
+     {2756081, 8598110, 7383731, -6859892, 22312759, -1105012, 21179801, 2600940, -9988298, -12506466},
+     {-24645692, 13317462, -30449259, -15653928, 21365574, -10869657, 11344424, 864440, -2499677, -16710063}},
+    {{-26432803, 6148329, -17184412, -14474154, 18782929, -275997, -22561534, 211300, 2719757, 4940997},
+     {-1323882, 3911313, -6948744, 14759765, -30027150, 7851207, 21690126, 8518463, 26699843, 5276295},
+     {-13149873, -6429067, 9396249, 365013, 24703301, -10488939, 1321586, 149635, -15452774, 7159369}},
+    {{9987780, -3404759, 17507962, 9505530, 9731535, -2165514, 22356009, 8312176, 22477218, -8403385},
+     {18155857, -16504990, 19744716, 9006923, 15154154, -10538976, 24256460, -4864995, -22548173, 9334109},
+     {2986088, -4911893, 10776628, -3473844, 10620590, -7083203, -21413845, 14253545, -22587149, 536906}},
+    {{4377756, 8115836, 24567078, 15495314, 11625074, 13064599, 7390551, 10589625, 10838060, -15420424},
+     {-19342404, 867880, 9277171, -3218459, -14431572, -1986443, 19295826, -15796950, 6378260, 699185},
+     {7895026, 4057113, -7081772, -13077756, -17886831, -323126, -716039, 15693155, -5045064, -13373962}},
+    {{-7737563, -5869402, -14566319, -7406919, 11385654, 13201616, 31730678, -10962840, -3918636, -9669325},
+     {10188286, -15770834, -7336361, 13427543, 22223443, 14896287, 30743455, 7116568, -21786507, 5427593},
+     {696102, 13206899, 27047647, -10632082, 15285305, -9853179, 10798490, -4578720, 19236243, 12477404}},
+    {{-11229439, 11243796, -17054270, -8040865, -788228, -8167967, -3897669, 11180504, -23169516, 7733644},
+     {17800790, -14036179, -27000429, -11766671, 23887827, 3149671, 23466177, -10538171, 10322027, 15313801},
+     {26246234, 11968874, 32263343, -5468728, 6830755, -13323031, -15794704, -101982, -24449242, 10890804}},
+    {{-31365647, 10271363, -12660625, -6267268, 16690207, -13062544, -14982212, 16484931, 25180797, -5334884},
+     {-586574, 10376444, -32586414, -11286356, 19801893, 10997610, 2276632, 9482883, 316878, 13820577},
+     {-9882808, -4510367, -2115506, 16457136, -11100081, 11674996, 30756178, -7515054, 30696930, -3712849}},
+    {{32988917, -9603412, 12499366, 7910787, -10617257, -11931514, -7342816, -9985397, -32349517, 7392473},
+     {-8855661, 15927861, 9866406, -3649411, -2396914, -16655781, -30409476, -9134995, 25112947, -2926644},
+     {-2504044, -436966, 25621774, -5678772, 15085042, -5479877, -24884878, -13526194, 5537438, -13914319}}
+  }, {
+    {{-11225584, 2320285, -9584280, 10149187, -33444663, 5808648, -14876251, -1729667, 31234590, 6090599},
+     {-9633316, 116426, 26083934, 2897444, -6364437, -2688086, 609721, 15878753, -6970405, -9034768},
+     {-27757857, 247744, -15194774, -9002551, 23288161, -10011936, -23869595, 6503646, 20650474, 1804084}},
+    {{-27589786, 15456424, 8972517, 8469608, 15640622, 4439847, 3121995, -10329713, 27842616, -202328},
+     {-15306973, 2839644, 22530074, 10026331, 4602058, 5048462, 28248656, 5031932, -11375082, 12714369},
+     {20807691, -7270825, 29286141, 11421711, -27876523, -13868230, -21227475, 1035546, -19733229, 12796920}},
+    {{12076899, -14301286, -8785001, -11848922, -25012791, 16400684, -17591495, -12899438, 3480665, -15182815},
+     {-32361549, 5457597, 28548107, 7833186, 7303070, -11953545, -24363064, -15921875, -33374054, 2771025},
+     {-21389266, 421932, 26597266, 6860826, 22486084, -6737172, -17137485, -4210226, -24552282, 15673397}},
+    {{-20184622, 2338216, 19788685, -9620956, -4001265, -8740893, -20271184, 4733254, 3727144, -12934448},
+     {6120119, 814863, -11794402, -622716, 6812205, -15747771, 2019594, 7975683, 31123697, -10958981},
+     {30069250, -11435332, 30434654, 2958439, 18399564, -976289, 12296869, 9204260, -16432438, 9648165}},
+    {{32705432, -1550977, 30705658, 7451065, -11805606, 9631813, 3305266, 5248604, -26008332, -11377501},
+     {17219865, 2375039, -31570947, -5575615, -19459679, 9219903, 294711, 15298639, 2662509, -16297073},
+     {-1172927, -7558695, -4366770, -4287744, -21346413, -8434326, 32087529, -1222777, 32247248, -14389861}},
+    {{14312628, 1221556, 17395390, -8700143, -4945741, -8684635, -28197744, -9637817, -16027623, -13378845},
+     {-1428825, -9678990, -9235681, 6549687, -7383069, -468664, 23046502, 9803137, 17597934, 2346211},
+     {18510800, 15337574, 26171504, 981392, -22241552, 7827556, -23491134, -11323352, 3059833, -11782870}},
+    {{10141598, 6082907, 17829293, -1947643, 9830092, 13613136, -25556636, -5544586, -33502212, 3592096},
+     {33114168, -15889352, -26525686, -13343397, 33076705, 8716171, 1151462, 1521897, -982665, -6837803},
+     {-32939165, -4255815, 23947181, -324178, -33072974, -12305637, -16637686, 3891704, 26353178, 693168}},
+    {{30374239, 1595580, -16884039, 13186931, 4600344, 406904, 9585294, -400668, 31375464, 14369965},
+     {-14370654, -7772529, 1510301, 6434173, -18784789, -6262728, 32732230, -13108839, 17901441, 16011505},
+     {18171223, -11934626, -12500402, 15197122, -11038147, -15230035, -19172240, -16046376, 8764035, 12309598}}
+  }, {
+    {{5975908, -5243188, -19459362, -9681747, -11541277, 14015782, -23665757, 1228319, 17544096, -10593782},
+     {5811932, -1715293, 3442887, -2269310, -18367348, -8359541, -18044043, -15410127, -5565381, 12348900},
+     {-31399660, 11407555, 25755363, 6891399, -3256938, 14872274, -24849353, 8141295, -10632534, -585479}},
+    {{-12675304, 694026, -5076145, 13300344, 14015258, -14451394, -9698672, -11329050, 30944593, 1130208},
+     {8247766, -6710942, -26562381, -7709309, -14401939, -14648910, 4652152, 2488540, 23550156, -271232},
+     {17294316, -3788438, 7026748, 15626851, 22990044, 113481, 2267737, -5908146, -408818, -137719}},
+    {{16091085, -16253926, 18599252, 7340678, 2137637, -1221657, -3364161, 14550936, 3260525, -7166271},
+     {-4910104, -13332887, 18550887, 10864893, -16459325, -7291596, -23028869, -13204905, -12748722, 2701326},
+     {-8574695, 16099415, 4629974, -16340524, -20786213, -6005432, -10018363, 9276971, 11329923, 1862132}},
+    {{14763076, -15903608, -30918270, 3689867, 3511892, 10313526, -21951088, 12219231, -9037963, -940300},
+     {8894987, -3446094, 6150753, 3013931, 301220, 15693451, -31981216, -2909717, -15438168, 11595570},
+     {15214962, 3537601, -26238722, -14058872, 4418657, -15230761, 13947276, 10730794, -13489462, -4363670}},
+    {{-2538306, 7682793, 32759013, 263109, -29984731, -7955452, -22332124, -10188635, 977108, 699994},
+     {-12466472, 4195084, -9211532, 550904, -15565337, 12917920, 19118110, -439841, -30534533, -14337913},
+     {31788461, -14507657, 4799989, 7372237, 8808585, -14747943, 9408237, -10051775, 12493932, -5409317}},
+    {{-25680606, 5260744, -19235809, -6284470, -3695942, 16566087, 27218280, 2607121, 29375955, 6024730},
+     {842132, -2794693, -4763381, -8722815, 26332018, -12405641, 11831880, 6985184, -9940361, 2854096},
+     {-4847262, -7969331, 2516242, -5847713, 9695691, -7221186, 16512645, 960770, 12121869, 16648078}},
+    {{-15218652, 14667096, -13336229, 2013717, 30598287, -464137, -31504922, -7882064, 20237806, 2838411},
+     {-19288047, 4453152, 15298546, -16178388, 22115043, -15972604, 12544294, -13470457, 1068881, -12499905},
+     {-9558883, -16518835, 33238498, 13506958, 30505848, -1114596, -8486907, -2630053, 12521378, 4845654}},
+    {{-28198521, 10744108, -2958380, 10199664, 7759311, -13088600, 3409348, -873400, -6482306, -12885870},
+     {-23561822, 6230156, -20382013, 10655314, -24040585, -11621172, 10477734, -1240216, -3113227, 13974498},
+     {12966261, 15550616, -32038948, -1615346, 21025980, -629444, 5642325, 7188737, 18895762, 12629579}}
+  }, {
+    {{14741879, -14946887, 22177208, -11721237, 1279741, 8058600, 11758140, 789443, 32195181, 3895677},
+     {10758205, 15755439, -4509950, 9243698, -4879422, 6879879, -2204575, -3566119, -8982069, 4429647},
+     {-2453894, 15725973, -20436342, -10410672, -5803908, -11040220, -7135870, -11642895, 18047436, -15281743}},
+    {{-25173001, -11307165, 29759956, 11776784, -22262383, -15820455, 10993114, -12850837, -17620701, -9408468},
+     {21987233, 700364, -24505048, 14972008, -7774265, -5718395, 32155026, 2581431, -29958985, 8773375},
+     {-25568350, 454463, -13211935, 16126715, 25240068, 8594567, 20656846, 12017935, -7874389, -13920155}},
+    {{6028182, 6263078, -31011806, -11301710, -818919, 2461772, -31841174, -5468042, -1721788, -2776725},
+     {-12278994, 16624277, 987579, -5922598, 32908203, 1248608, 7719845, -4166698, 28408820, 6816612},
+     {-10358094, -8237829, 19549651, -12169222, 22082623, 16147817, 20613181, 13982702, -10339570, 5067943}},
+    {{-30505967, -3821767, 12074681, 13582412, -19877972, 2443951, -19719286, 12746132, 5331210, -10105944},
+     {30528811, 3601899, -1957090, 4619785, -27361822, -15436388, 24180793, -12570394, 27679908, -1648928},
+     {9402404, -13957065, 32834043, 10838634, -26580150, -13237195, 26653274, -8685565, 22611444, -12715406}},
+    {{22190590, 1118029, 22736441, 15130463, -30460692, -5991321, 19189625, -4648942, 4854859, 6622139},
+     {-8310738, -2953450, -8262579, -3388049, -10401731, -271929, 13424426, -3567227, 26404409, 13001963},
+     {-31241838, -15415700, -2994250, 8939346, 11562230, -12840670, -26064365, -11621720, -15405155, 11020693}},
+    {{1866042, -7949489, -7898649, -10301010, 12483315, 13477547, 3175636, -12424163, 28761762, 1406734},
+     {-448555, -1777666, 13018551, 3194501, -9580420, -11161737, 24760585, -4347088, 25577411, -13378680},
+     {-24290378, 4759345, -690653, -1852816, 2066747, 10693769, -29595790, 9884936, -9368926, 4745410}},
+    {{-9141284, 6049714, -19531061, -4341411, -31260798, 9944276, -15462008, -11311852, 10931924, -11931931},
+     {-16561513, 14112680, -8012645, 4817318, -8040464, -11414606, -22853429, 10856641, -20470770, 13434654},
+     {22759489, -10073434, -16766264, -1871422, 13637442, -10168091, 1765144, -12654326, 28445307, -5364710}},
+    {{29875063, 12493613, 2795536, -3786330, 1710620, 15181182, -10195717, -8788675, 9074234, 1167180},
+     {-26205683, 11014233, -9842651, -2635485, -26908120, 7532294, -18716888, -9535498, 3843903, 9367684},
+     {-10969595, -6403711, 9591134, 9582310, 11349256, 108879, 16235123, 8601684, -139197, 4242895}}
+  }, {
+    {{22092954, -13191123, -2042793, -11968512, 32186753, -11517388, -6574341, 2470660, -27417366, 16625501},
+     {-11057722, 3042016, 13770083, -9257922, 584236, -544855, -7770857, 2602725, -27351616, 14247413},
+     {6314175, -10264892, -32772502, 15957557, -10157730, 168750, -8618807, 14290061, 27108877, -1180880}},
+    {{-8586597, -7170966, 13241782, 10960156, -32991015, -13794596, 33547976, -11058889, -27148451, 981874},
+     {22833440, 9293594, -32649448, -13618667, -9136966, 14756819, -22928859, -13970780, -10479804, -16197962},
+     {-7768587, 3326786, -28111797, 10783824, 19178761, 14905060, 22680049, 13906969, -15933690, 3797899}},
+    {{21721356, -4212746, -12206123, 9310182, -3882239, -13653110, 23740224, -2709232, 20491983, -8042152},
+     {9209270, -15135055, -13256557, -6167798, -731016, 15289673, 25947805, 15286587, 30997318, -6703063},
+     {7392032, 16618386, 23946583, -8039892, -13265164, -1533858, -14197445, -2321576, 17649998, -250080}},
+    {{-9301088, -14193827, 30609526, -3049543, -25175069, -1283752, -15241566, -9525724, -2233253, 7662146},
+     {-17558673, 1763594, -33114336, 15908610, -30040870, -12174295, 7335080, -8472199, -3174674, 3440183},
+     {-19889700, -5977008, -24111293, -9688870, 10799743, -16571957, 40450, -4431835, 4862400, 1133}},
+    {{-32856209, -7873957, -5422389, 14860950, -16319031, 7956142, 7258061, 311861, -30594991, -7379421},
+     {-3773428, -1565936, 28985340, 7499440, 24445838, 9325937, 29727763, 16527196, 18278453, 15405622},
+     {-4381906, 8508652, -19898366, -3674424, -5984453, 15149970, -13313598, 843523, -21875062, 13626197}},
+    {{2281448, -13487055, -10915418, -2609910, 1879358, 16164207, -10783882, 3953792, 13340839, 15928663},
+     {31727126, -7179855, -18437503, -8283652, 2875793, -16390330, -25269894, -7014826, -23452306, 5964753},
+     {4100420, -5959452, -17179337, 6017714, -18705837, 12227141, -26684835, 11344144, 2538215, -7570755}},
+    {{-9433605, 6123113, 11159803, -2156608, 30016280, 14966241, -20474983, 1485421, -629256, -15958862},
+     {-26804558, 4260919, 11851389, 9658551, -32017107, 16367492, -20205425, -13191288, 11659922, -11115118},
+     {26180396, 10015009, -30844224, -8581293, 5418197, 9480663, 2231568, -10170080, 33100372, -1306171}},
+    {{15121113, -5201871, -10389905, 15427821, -27509937, -15992507, 21670947, 4486675, -5931810, -14466380},
+     {16166486, -9483733, -11104130, 6023908, -31926798, -1364923, 2340060, -16254968, -10735770, -10039824},
+     {28042865, -3557089, -12126526, 12259706, -3717498, -6945899, 6766453, -8689599, 18036436, 5803270}}
+  }, {
+    {{-817581, 6763912, 11803561, 1585585, 10958447, -2671165, 23855391, 4598332, -6159431, -14117438},
+     {-31031306, -14256194, 17332029, -2383520, 31312682, -5967183, 696309, 50292, -20095739, 11763584},
+     {-594563, -2514283, -32234153, 12643980, 12650761, 14811489, 665117, -12613632, -19773211, -10713562}},
+    {{30464590, -11262872, -4127476, -12734478, 19835327, -7105613, -24396175, 2075773, -17020157, 992471},
+     {18357185, -6994433, 7766382, 16342475, -29324918, 411174, 14578841, 8080033, -11574335, -10601610},
+     {19598397, 10334610, 12555054, 2555664, 18821899, -10339780, 21873263, 16014234, 26224780, 16452269}},
+    {{-30223925, 5145196, 5944548, 16385966, 3976735, 2009897, -11377804, -7618186, -20533829, 3698650},
+     {14187449, 3448569, -10636236, -10810935, -22663880, -3433596, 7268410, -10890444, 27394301, 12015369},
+     {19695761, 16087646, 28032085, 12999827, 6817792, 11427614, 20244189, -1312777, -13259127, -3402461}},
+    {{30860103, 12735208, -1888245, -4699734, -16974906, 2256940, -8166013, 12298312, -8550524, -10393462},
+     {-5719826, -11245325, -1910649, 15569035, 26642876, -7587760, -5789354, -15118654, -4976164, 12651793},
+     {-2848395, 9953421, 11531313, -5282879, 26895123, -12697089, -13118820, -16517902, 9768698, -2533218}},
+    {{-24719459, 1894651, -287698, -4704085, 15348719, -8156530, 32767513, 12765450, 4940095, 10678226},
+     {18860224, 15980149, -18987240, -1562570, -26233012, -11071856, -7843882, 13944024, -24372348, 16582019},
+     {-15504260, 4970268, -29893044, 4175593, -20993212, -2199756, -11704054, 15444560, -11003761, 7989037}},
+    {{31490452, 5568061, -2412803, 2182383, -32336847, 4531686, -32078269, 6200206, -19686113, -14800171},
+     {-17308668, -15879940, -31522777, -2831, -32887382, 16375549, 8680158, -16371713, 28550068, -6857132},
+     {-28126887, -5688091, 16837845, -1820458, -6850681, 12700016, -30039981, 4364038, 1155602, 5988841}},
+    {{21890435, -13272907, -12624011, 12154349, -7831873, 15300496, 23148983, -4470481, 24618407, 8283181},
+     {-33136107, -10512751, 9975416, 6841041, -31559793, 16356536, 3070187, -7025928, 1466169, 10740210},
+     {-1509399, -15488185, -13503385, -10655916, 32799044, 909394, -13938903, -5779719, -32164649, -15327040}},
+    {{3960823, -14267803, -28026090, -15918051, -19404858, 13146868, 15567327, 951507, -3260321, -573935},
+     {24740841, 5052253, -30094131, 8961361, 25877428, 6165135, -24368180, 14397372, -7380369, -6144105},
+     {-28888365, 3510803, -28103278, -1158478, -11238128, -10631454, -15441463, -14453128, -1625486, -6494814}}
+  }, {
+    {{793299, -9230478, 8836302, -6235707, -27360908, -2369593, 33152843, -4885251, -9906200, -621852},
+     {5666233, 525582, 20782575, -8038419, -24538499, 14657740, 16099374, 1468826, -6171428, -15186581},
+     {-4859255, -3779343, -2917758, -6748019, 7778750, 11688288, -30404353, -9871238, -1558923, -9863646}},
+    {{10896332, -7719704, 824275, 472601, -19460308, 3009587, 25248958, 14783338, -30581476, -15757844},
+     {10566929, 12612572, -31944212, 11118703, -12633376, 12362879, 21752402, 8822496, 24003793, 14264025},
+     {27713862, -7355973, -11008240, 9227530, 27050101, 2504721, 23886875, -13117525, 13958495, -5732453}},
+    {{-23481610, 4867226, -27247128, 3900521, 29838369, -8212291, -31889399, -10041781, 7340521, -15410068},
+     {4646514, -8011124, -22766023, -11532654, 23184553, 8566613, 31366726, -1381061, -15066784, -10375192},
+     {-17270517, 12723032, -16993061, 14878794, 21619651, -6197576, 27584817, 3093888, -8843694, 3849921}},
+    {{-9064912, 2103172, 25561640, -15125738, -5239824, 9582958, 32477045, -9017955, 5002294, -15550259},
+     {-12057553, -11177906, 21115585, -13365155, 8808712, -12030708, 16489530, 13378448, -25845716, 12741426},
+     {-5946367, 10645103, -30911586, 15390284, -3286982, -7118677, 24306472, 15852464, 28834118, -7646072}},
+    {{-17335748, -9107057, -24531279, 9434953, -8472084, -583362, -13090771, 455841, 20461858, 5491305},
+     {13669248, -16095482, -12481974, -10203039, -14569770, -11893198, -24995986, 11293807, -28588204, -9421832},
+     {28497928, 6272777, -33022994, 14470570, 8906179, -1225630, 18504674, -14165166, 29867745, -8795943}},
+    {{-16207023, 13517196, -27799630, -13697798, 24009064, -6373891, -6367600, -13175392, 22853429, -4012011},
+     {24191378, 16712145, -13931797, 15217831, 14542237, 1646131, 18603514, -11037887, 12876623, -2112447},
+     {17902668, 4518229, -411702, -2829247, 26878217, 5258055, -12860753, 608397, 16031844, 3723494}},
+    {{-28632773, 12763728, -20446446, 7577504, 33001348, -13017745, 17558842, -7872890, 23896954, -4314245},
+     {-20005381, -12011952, 31520464, 605201, 2543521, 5991821, -2945064, 7229064, -9919646, -8826859},
+     {28816045, 298879, -28165016, -15920938, 19000928, -1665890, -12680833, -2949325, -18051778, -2082915}},
+    {{16000882, -344896, 3493092, -11447198, -29504595, -13159789, 12577740, 16041268, -19715240, 7847707},
+     {10151868, 10572098, 27312476, 7922682, 14825339, 4723128, -32855931, -6519018, -10020567, 3852848},
+     {-11430470, 15697596, -21121557, -4420647, 5386314, 15063598, 16514493, -15932110, 29330899, -15076224}}
+  }, {
+    {{-25499735, -4378794, -15222908, -6901211, 16615731, 2051784, 3303702, 15490, -27548796, 12314391},
+     {15683520, -6003043, 18109120, -9980648, 15337968, -5997823, -16717435, 15921866, 16103996, -3731215},
+     {-23169824, -10781249, 13588192, -1628807, -3798557, -1074929, -19273607, 5402699, -29815713, -9841101}},
+    {{23190676, 2384583, -32714340, 3462154, -29903655, -1529132, -11266856, 8911517, -25205859, 2739713},
+     {21374101, -3554250, -33524649, 9874411, 15377179, 11831242, -33529904, 6134907, 4931255, 11987849},
+     {-7732, -2978858, -16223486, 7277597, 105524, -322051, -31480539, 13861388, -30076310, 10117930}},
+    {{-29501170, -10744872, -26163768, 13051539, -25625564, 5089643, -6325503, 6704079, 12890019, 15728940},
+     {-21972360, -11771379, -951059, -4418840, 14704840, 2695116, 903376, -10428139, 12885167, 8311031},
+     {-17516482, 5352194, 10384213, -13811658, 7506451, 13453191, 26423267, 4384730, 1888765, -5435404}},
+    {{-25817338, -3107312, -13494599, -3182506, 30896459, -13921729, -32251644, -12707869, -19464434, -3340243},
+     {-23607977, -2665774, -526091, 4651136, 5765089, 4618330, 6092245, 14845197, 17151279, -9854116},
+     {-24830458, -12733720, -15165978, 10367250, -29530908, -265356, 22825805, -7087279, -16866484, 16176525}},
+    {{-23583256, 6564961, 20063689, 3798228, -4740178, 7359225, 2006182, -10363426, -28746253, -10197509},
+     {-10626600, -4486402, -13320562, -5125317, 3432136, -6393229, 23632037, -1940610, 32808310, 1099883},
+     {15030977, 5768825, -27451236, -2887299, -6427378, -15361371, -15277896, -6809350, 2051441, -15225865}},
+    {{-3362323, -7239372, 7517890, 9824992, 23555850, 295369, 5148398, -14154188, -22686354, 16633660},
+     {4577086, -16752288, 13249841, -15304328, 19958763, -14537274, 18559670, -10759549, 8402478, -9864273},
+     {-28406330, -1051581, -26790155, -907698, -17212414, -11030789, 9453451, -14980072, 17983010, 9967138}},
+    {{-25762494, 6524722, 26585488, 9969270, 24709298, 1220360, -1677990, 7806337, 17507396, 3651560},
+     {-10420457, -4118111, 14584639, 15971087, -15768321, 8861010, 26556809, -5574557, -18553322, -11357135},
+     {2839101, 14284142, 4029895, 3472686, 14402957, 12689363, -26642121, 8459447, -5605463, -7621941}},
+    {{-4839289, -3535444, 9744961, 2871048, 25113978, 3187018, -25110813, -849066, 17258084, -7977739},
+     {18164541, -10595176, -17154882, -1542417, 19237078, -9745295, 23357533, -15217008, 26908270, 12150756},
+     {-30264870, -7647865, 5112249, -7036672, -1499807, -6974257, 43168, -5537701, -32302074, 16215819}}
+  }, {
+    {{-6898905, 9824394, -12304779, -4401089, -31397141, -6276835, 32574489, 12532905, -7503072, -8675347},
+     {-27343522, -16515468, -27151524, -10722951, 946346, 16291093, 254968, 7168080, 21676107, -1943028},
+     {21260961, -8424752, -16831886, -11920822, -23677961, 3968121, -3651949, -6215466, -3556191, -7913075}},
+    {{16544754, 13250366, -16804428, 15546242, -4583003, 12757258, -2462308, -8680336, -18907032, -9662799},
+     {-2415239, -15577728, 18312303, 4964443, -15272530, -12653564, 26820651, 16690659, 25459437, -4564609},
+     {-25144690, 11425020, 28423002, -11020557, -6144921, -15826224, 9142795, -2391602, -6432418, -1644817}},
+    {{-23104652, 6253476, 16964147, -3768872, -25113972, -12296437, -27457225, -16344658, 6335692, 7249989},
+     {-30333227, 13979675, 7503222, -12368314, -11956721, -4621693, -30272269, 2682242, 25993170, -12478523},
+     {4364628, 5930691, 32304656, -10044554, -8054781, 15091131, 22857016, -10598955, 31820368, 15075278}},
+    {{31879134, -8918693, 17258761, 90626, -8041836, -4917709, 24162788, -9650886, -17970238, 12833045},
+     {19073683, 14851414, -24403169, -11860168, 7625278, 11091125, -19619190, 2074449, -9413939, 14905377},
+     {24483667, -11935567, -2518866, -11547418, -1553130, 15355506, -25282080, 9253129, 27628530, -7555480}},
+    {{17597607, 8340603, 19355617, 552187, 26198470, -3176583, 4593324, -9157582, -14110875, 15297016},
+     {510886, 14337390, -31785257, 16638632, 6328095, 2713355, -20217417, -11864220, 8683221, 2921426},
+     {18606791, 11874196, 27155355, -5281482, -24031742, 6265446, -25178240, -1278924, 4674690, 13890525}},
+    {{13609624, 13069022, -27372361, -13055908, 24360586, 9592974, 14977157, 9835105, 4389687, 288396},
+     {9922506, -519394, 13613107, 5883594, -18758345, -434263, -12304062, 8317628, 23388070, 16052080},
+     {12720016, 11937594, -31970060, -5028689, 26900120, 8561328, -20155687, -11632979, -14754271, -10812892}},
+    {{15961858, 14150409, 26716931, -665832, -22794328, 13603569, 11829573, 7467844, -28822128, 929275},
+     {11038231, -11582396, -27310482, -7316562, -10498527, -16307831, -23479533, -9371869, -21393143, 2465074},
+     {20017163, -4323226, 27915242, 1529148, 12396362, 15675764, 13817261, -9658066, 2463391, -4622140}},
+    {{-16358878, -12663911, -12065183, 4996454, -1256422, 1073572, 9583558, 12851107, 4003896, 12673717},
+     {-1731589, -15155870, -3262930, 16143082, 19294135, 13385325, 14741514, -9103726, 7903886, 2348101},
+     {24536016, -16515207, 12715592, -3862155, 1511293, 10047386, -3842346, -7129159, -28377538, 10048127}}
+  }, {
+    {{-12622226, -6204820, 30718825, 2591312, -10617028, 12192840, 18873298, -7297090, -32297756, 15221632},
+     {-26478122, -11103864, 11546244, -1852483, 9180880, 7656409, -21343950, 2095755, 29769758, 6593415},
+     {-31994208, -2907461, 4176912, 3264766, 12538965, -868111, 26312345, -6118678, 30958054, 8292160}},
+    {{31429822, -13959116, 29173532, 15632448, 12174511, -2760094, 32808831, 3977186, 26143136, -3148876},
+     {22648901, 1402143, -22799984, 13746059, 7936347, 365344, -8668633, -1674433, -3758243, -2304625},
+     {-15491917, 8012313, -2514730, -12702462, -23965846, -10254029, -1612713, -1535569, -16664475, 8194478}},
+    {{27338066, -7507420, -7414224, 10140405, -19026427, -6589889, 27277191, 8855376, 28572286, 3005164},
+     {26287124, 4821776, 25476601, -4145903, -3764513, -15788984, -18008582, 1182479, -26094821, -13079595},
+     {-7171154, 3178080, 23970071, 6201893, -17195577, -4489192, -21876275, -13982627, 32208683, -1198248}},
+    {{-16657702, 2817643, -10286362, 14811298, 6024667, 13349505, -27315504, -10497842, -27672585, -11539858},
+     {15941029, -9405932, -21367050, 8062055, 31876073, -238629, -15278393, -1444429, 15397331, -4130193},
+     {8934485, -13485467, -23286397, -13423241, -32446090, 14047986, 31170398, -1441021, -27505566, 15087184}},
+    {{-18357243, -2156491, 24524913, -16677868, 15520427, -6360776, -15502406, 11461896, 16788528, -5868942},
+     {-1947386, 16013773, 21750665, 3714552, -17401782, -16055433, -3770287, -10323320, 31322514, -11615635},
+     {21426655, -5650218, -13648287, -5347537, -28812189, -4920970, -18275391, -14621414, 13040862, -12112948}},
+    {{11293895, 12478086, -27136401, 15083750, -29307421, 14748872, 14555558, -13417103, 1613711, 4896935},
+     {-25894883, 15323294, -8489791, -8057900, 25967126, -13425460, 2825960, -4897045, -23971776, -11267415},
+     {-15924766, -5229880, -17443532, 6410664, 3622847, 10243618, 20615400, 12405433, -23753030, -8436416}},
+    {{-7091295, 12556208, -20191352, 9025187, -17072479, 4333801, 4378436, 2432030, 23097949, -566018},
+     {4565804, -16025654, 20084412, -7842817, 1724999, 189254, 24767264, 10103221, -18512313, 2424778},
+     {366633, -11976806, 8173090, -6890119, 30788634, 5745705, -7168678, 1344109, -3642553, 12412659}},
+    {{-24001791, 7690286, 14929416, -168257, -32210835, -13412986, 24162697, -15326504, -3141501, 11179385},
+     {18289522, -14724954, 8056945, 16430056, -21729724, 7842514, -6001441, -1486897, -18684645, -11443503},
+     {476239, 6601091, -6152790, -9723375, 17503545, -4863900, 27672959, 13403813, 11052904, 5219329}}
+  }, {
+    {{20678546, -8375738, -32671898, 8849123, -5009758, 14574752, 31186971, -3973730, 9014762, -8579056},
+     {-13644050, -10350239, -15962508, 5075808, -1514661, -11534600, -33102500, 9160280, 8473550, -3256838},
+     {24900749, 14435722, 17209120, -15292541, -22592275, 9878983, -7689309, -16335821, -24568481, 11788948}},
+    {{-3118155, -11395194, -13802089, 14797441, 9652448, -6845904, -20037437, 10410733, -24568470, -1458691},
+     {-15659161, 16736706, -22467150, 10215878, -9097177, 7563911, 11871841, -12505194, -18513325, 8464118},
+     {-23400612, 8348507, -14585951, -861714, -3950205, -6373419, 14325289, 8628612, 33313881, -8370517}},
+    {{-20186973, -4967935, 22367356, 5271547, -1097117, -4788838, -24805667, -10236854, -8940735, -5818269},
+     {-6948785, -1795212, -32625683, -16021179, 32635414, -7374245, 15989197, -12838188, 28358192, -4253904},
+     {-23561781, -2799059, -32351682, -1661963, -9147719, 10429267, -16637684, 4072016, -5351664, 5596589}},
+    {{-28236598, -3390048, 12312896, 6213178, 3117142, 16078565, 29266239, 2557221, 1768301, 15373193},
+     {-7243358, -3246960, -4593467, -7553353, -127927, -912245, -1090902, -4504991, -24660491, 3442910},
+     {-30210571, 5124043, 14181784, 8197961, 18964734, -11939093, 22597931, 7176455, -18585478, 13365930}},
+    {{-7877390, -1499958, 8324673, 4690079, 6261860, 890446, 24538107, -8570186, -9689599, -3031667},
+     {25008904, -10771599, -4305031, -9638010, 16265036, 15721635, 683793, -11823784, 15723479, -15163481},
+     {-9660625, 12374379, -27006999, -7026148, -7724114, -12314514, 11879682, 5400171, 519526, -1235876}},
+    {{22258397, -16332233, -7869817, 14613016, -22520255, -2950923, -20353881, 7315967, 16648397, 7605640},
+     {-8081308, -8464597, -8223311, 9719710, 19259459, -15348212, 23994942, -5281555, -9468848, 4763278},
+     {-21699244, 9220969, -15730624, 1084137, -25476107, -2852390, 31088447, -7764523, -11356529, 728112}},
+    {{26047220, -11751471, -6900323, -16521798, 24092068, 9158119, -4273545, -12555558, -29365436, -5498272},
+     {17510331, -322857, 5854289, 8403524, 17133918, -3112612, -28111007, 12327945, 10750447, 10014012},
+     {-10312768, 3936952, 9156313, -8897683, 16498692, -994647, -27481051, -666732, 3424691, 7540221}},
+    {{30322361, -6964110, 11361005, -4143317, 7433304, 4989748, -7071422, -16317219, -9244265, 15258046},
+     {13054562, -2779497, 19155474, 469045, -12482797, 4566042, 5631406, 2711395, 1062915, -5136345},
+     {-19240248, -11254599, -29509029, -7499965, -5835763, 13005411, -6066489, 12194497, 32960380, 1459310}}
+  }, {
+    {{19852034, 7027924, 23669353, 10020366, 8586503, -6657907, 394197, -6101885, 18638003, -11174937},
+     {31395534, 15098109, 26581030, 8030562, -16527914, -5007134, 9012486, -7584354, -6643087, -5442636},
+     {-9192165, -2347377, -1997099, 4529534, 25766844, 607986, -13222, 9677543, -32294889, -6456008}},
+    {{-2444496, -149937, 29348902, 8186665, 1873760, 12489863, -30934579, -7839692, -7852844, -8138429},
+     {-15236356, -15433509, 7766470, 746860, 26346930, -10221762, -27333451, 10754588, -9431476, 5203576},
+     {31834314, 14135496, -770007, 5159118, 20917671, -16768096, -7467973, -7337524, 31809243, 7347066}},
+    {{-9606723, -11874240, 20414459, 13033986, 13716524, -11691881, 19797970, -12211255, 15192876, -2087490},
+     {-12663563, -2181719, 1168162, -3804809, 26747877, -14138091, 10609330, 12694420, 33473243, -13382104},
+     {33184999, 11180355, 15832085, -11385430, -1633671, 225884, 15089336, -11023903, -6135662, 14480053}},
+    {{31308717, -5619998, 31030840, -1897099, 15674547, -6582883, 5496208, 13685227, 27595050, 8737275},
+     {-20318852, -15150239, 10933843, -16178022, 8335352, -7546022, -31008351, -12610604, 26498114, 66511},
+     {22644454, -8761729, -16671776, 4884562, -3105614, -13559366, 30540766, -4286747, -13327787, -7515095}},
+    {{-28017847, 9834845, 18617207, -2681312, -3401956, -13307506, 8205540, 13585437, -17127465, 15115439},
+     {23711543, -672915, 31206561, -8362711, 6164647, -9709987, -33535882, -1426096, 8236921, 16492939},
+     {-23910559, -13515526, -26299483, -4503841, 25005590, -7687270, 19574902, 10071562, 6708380, -6222424}},
+    {{2101391, -4930054, 19702731, 2367575, -15427167, 1047675, 5301017, 9328700, 29955601, -11678310},
+     {3096359, 9271816, -21620864, -15521844, -14847996, -7592937, -25892142, -12635595, -9917575, 6216608},
+     {-32615849, 338663, -25195611, 2510422, -29213566, -13820213, 24822830, -6146567, -26767480, 7525079}},
+    {{-23066649, -13985623, 16133487, -7896178, -3389565, 778788, -910336, -2782495, -19386633, 11994101},
+     {21691500, -13624626, -641331, -14367021, 3285881, -3483596, -25064666, 9718258, -7477437, 13381418},
+     {18445390, -4202236, 14979846, 11622458, -1727110, -3582980, 23111648, -6375247, 28535282, 15779576}},
+    {{30098053, 3089662, -9234387, 16662135, -21306940, 11308411, -14068454, 12021730, 9955285, -16303356},
+     {9734894, -14576830, -7473633, -9138735, 2060392, 11313496, -18426029, 9924399, 20194861, 13380996},
+     {-26378102, -7965207, -22167821, 15789297, -18055342, -6168792, -1984914, 15707771, 26342023, 10146099}}
+  }, {
+    {{-26016874, -219943, 21339191, -41388, 19745256, -2878700, -29637280, 2227040, 21612326, -545728},
+     {-13077387, 1184228, 23562814, -5970442, -20351244, -6348714, 25764461, 12243797, -20856566, 11649658},
+     {-10031494, 11262626, 27384172, 2271902, 26947504, -15997771, 39944, 6114064, 33514190, 2333242}},
+    {{-21433588, -12421821, 8119782, 7219913, -21830522, -9016134, -6679750, -12670638, 24350578, -13450001},
+     {-4116307, -11271533, -23886186, 4843615, -30088339, 690623, -31536088, -10406836, 8317860, 12352766},
+     {18200138, -14475911, -33087759, -2696619, -23702521, -9102511, -23552096, -2287550, 20712163, 6719373}},
+    {{26656208, 6075253, -7858556, 1886072, -28344043, 4262326, 11117530, -3763210, 26224235, -3297458},
+     {-17168938, -14854097, -3395676, -16369877, -19954045, 14050420, 21728352, 9493610, 18620611, -16428628},
+     {-13323321, 13325349, 11432106, 5964811, 18609221, 6062965, -5269471, -9725556, -30701573, -16479657}},
+    {{-23860538, -11233159, 26961357, 1640861, -32413112, -16737940, 12248509, -5240639, 13735342, 1934062},
+     {25089769, 6742589, 17081145, -13406266, 21909293, -16067981, -15136294, -3765346, -21277997, 5473616},
+     {31883677, -7961101, 1083432, -11572403, 22828471, 13290673, -7125085, 12469656, 29111212, -5451014}},
+    {{24244947, -15050407, -26262976, 2791540, -14997599, 16666678, 24367466, 6388839, -10295587, 452383},
+     {-25640782, -3417841, 5217916, 16224624, 19987036, -4082269, -24236251, -5915248, 15766062, 8407814},
+     {-20406999, 13990231, 15495425, 16395525, 5377168, 15166495, -8917023, -4388953, -8067909, 2276718}},
+    {{30157918, 12924066, -17712050, 9245753, 19895028, 3368142, -23827587, 5096219, 22740376, -7303417},
+     {2041139, -14256350, 7783687, 13876377, -25946985, -13352459, 24051124, 13742383, -15637599, 13295222},
+     {33338237, -8505733, 12532113, 7977527, 9106186, -1715251, -17720195, -4612972, -4451357, -14669444}},
+    {{-20045281, 5454097, -14346548, 6447146, 28862071, 1883651, -2469266, -4141880, 7770569, 9620597},
+     {23208068, 7979712, 33071466, 8149229, 1758231, -10834995, 30945528, -1694323, -33502340, -14767970},
+     {1439958, -16270480, -1079989, -793782, 4625402, 10647766, -5043801, 1220118, 30494170, -11440799}},
+    {{-5037580, -13028295, -2970559, -3061767, 15640974, -6701666, -26739026, 926050, -1684339, -13333647},
+     {13908495, -3549272, 30919928, -6273825, -21521863, 7989039, 9021034, 9078865, 3353509, 4033511},
+     {-29663431, -15113610, 32259991, -344482, 24295849, -12912123, 23161163, 8839127, 27485041, 7356032}}
+  }, {
+    {{9661027, 705443, 11980065, -5370154, -1628543, 14661173, -6346142, 2625015, 28431036, -16771834},
+     {-23839233, -8311415, -25945511, 7480958, -17681669, -8354183, -22545972, 14150565, 15970762, 4099461},
+     {29262576, 16756590, 26350592, -8793563, 8529671, -11208050, 13617293, -9937143, 11465739, 8317062}},
+    {{-25493081, -6962928, 32500200, -9419051, -23038724, -2302222, 14898637, 3848455, 20969334, -5157516},
+     {-20384450, -14347713, -18336405, 13884722, -33039454, 2842114, -21610826, -3649888, 11177095, 14989547},
+     {-24496721, -11716016, 16959896, 2278463, 12066309, 10137771, 13515641, 2581286, -28487508, 9930240}},
+    {{-17751622, -2097826, 16544300, -13009300, -15914807, -14949081, 18345767, -13403753, 16291481, -5314038},
+     {-33229194, 2553288, 32678213, 9875984, 8534129, 6889387, -9676774, 6957617, 4368891, 9788741},
+     {16660756, 7281060, -10830758, 12911820, 20108584, -8101676, -21722536, -8613148, 16250552, -11111103}},
+    {{-19765507, 2390526, -16551031, 14161980, 1905286, 6414907, 4689584, 10604807, -30190403, 4782747},
+     {-1354539, 14736941, -7367442, -13292886, 7710542, -14155590, -9981571, 4383045, 22546403, 437323},
+     {31665577, -12180464, -16186830, 1491339, -18368625, 3294682, 27343084, 2786261, -30633590, -14097016}},
+    {{-14467279, -683715, -33374107, 7448552, 19294360, 14334329, -19690631, 2355319, -19284671, -6114373},
+     {15121312, -15796162, 6377020, -6031361, -10798111, -12957845, 18952177, 15496498, -29380133, 11754228},
+     {-2637277, -13483075, 8488727, -14303896, 12728761, -1622493, 7141596, 11724556, 22761615, -10134141}},
+    {{16918416, 11729663, -18083579, 3022987, -31015732, -13339659, -28741185, -12227393, 32851222, 11717399},
+     {11166634, 7338049, -6722523, 4531520, -29468672, -7302055, 31474879, 3483633, -1193175, -4030831},
+     {-185635, 9921305, 31456609, -13536438, -12013818, 13348923, 33142652, 6546660, -19985279, -3948376}},
+    {{-32460596, 11266712, -11197107, -7899103, 31703694, 3855903, -8537131, -12833048, -30772034, -15486313},
+     {-18006477, 12709068, 3991746, -6479188, -21491523, -10550425, -31135347, -16049879, 10928917, 3011958},
+     {-6957757, -15594337, 31696059, 334240, 29576716, 14796075, -30831056, -12805180, 18008031, 10258577}},
+    {{-22448644, 15655569, 7018479, -4410003, -30314266, -1201591, -1853465, 1367120, 25127874, 6671743},
+     {29701166, -14373934, -10878120, 9279288, -17568, 13127210, 21382910, 11042292, 25838796, 4642684},
+     {-20430234, 14955537, -24126347, 8124619, -5369288, -5990470, 30468147, -13900640, 18423289, 4177476}}
+  }
+};
+
+const ge_precomp ge_Bi[8] = {
+  {{25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605},
+   {-12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378},
+   {-8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546}}, {{15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024},
+   {16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574},
+   {30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357}}, {{10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380},
+   {4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306},
+   {19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942}}, {{5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766},
+   {-30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701},
+   {28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300}}, {{-22518993, -6692182, 14201702, -8745502, -23510406, 8844726, 18474211, -1361450, -13062696, 13821877},
+   {-6455177, -7839871, 3374702, -4740862, -27098617, -10571707, 31655028, -7212327, 18853322, -14220951},
+   {4566830, -12963868, -28974889, -12240689, -7602672, -2830569, -8514358, -10431137, 2207753, -3209784}}, {{-25154831, -4185821, 29681144, 7868801, -6854661, -9423865, -12437364, -663000, -31111463, -16132436},
+   {25576264, -2703214, 7349804, -11814844, 16472782, 9300885, 3844789, 15725684, 171356, 6466918},
+   {23103977, 13316479, 9739013, -16149481, 817875, -15038942, 8965339, -14088058, -30714912, 16193877}}, {{-33521811, 3180713, -2394130, 14003687, -16903474, -16270840, 17238398, 4729455, -18074513, 9256800},
+   {-25182317, -4174131, 32336398, 5036987, -21236817, 11360617, 22616405, 9761698, -19827198, 630305},
+   {-13720693, 2639453, -24237460, -7406481, 9494427, -5774029, -6554551, -15960994, -2449256, -14291300}}, {{-3151181, -5046075, 9282714, 6866145, -31907062, -863023, -18940575, 15033784, 25105118, -7894876},
+   {-24326370, 15950226, -31801215, -14592823, -11662737, -5090925, 1573892, -2625887, 2198790, -15804619},
+   {-3099351, 10324967, -2241613, 7453183, -5446979, -2735503, -13812022, -16236442, -32461234, -12290683}}
+};
+
+/* A = 2 * (1 - d) / (1 + d) = 486662 */
+const fe fe_ma2 = {-12721188, -3529, 0, 0, 0, 0, 0, 0, 0, 0}; /* -A^2 */
+const fe fe_ma = {-486662, 0, 0, 0, 0, 0, 0, 0, 0, 0}; /* -A */
+const fe fe_fffb1 = {-31702527, -2466483, -26106795, -12203692, -12169197, -321052, 14850977, -10296299, -16929438, -407568}; /* sqrt(-2 * A * (A + 2)) */
+const fe fe_fffb2 = {8166131, -6741800, -17040804, 3154616, 21461005, 1466302, -30876704, -6368709, 10503587, -13363080}; /* sqrt(2 * A * (A + 2)) */
+const fe fe_fffb3 = {-13620103, 14639558, 4532995, 7679154, 16815101, -15883539, -22863840, -14813421, 13716513, -6477756}; /* sqrt(-sqrt(-1) * A * (A + 2)) */
+const fe fe_fffb4 = {-21786234, -12173074, 21573800, 4524538, -4645904, 16204591, 8012863, -8444712, 3212926, 6885324}; /* sqrt(sqrt(-1) * A * (A + 2)) */
diff --git a/crypt/monero_crypto/crypto-ops.c b/crypt/monero_crypto/crypto-ops.c
new file mode 100644
index 0000000000..b5c62bce43
--- /dev/null
+++ b/crypt/monero_crypto/crypto-ops.c
@@ -0,0 +1,3580 @@
+// 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
+
+#include <assert.h>
+#include <stdint.h>
+
+#include "warnings.h"
+#include "crypto-ops.h"
+
+DISABLE_VS_WARNINGS(4146 4244)
+
+/* Predeclarations */
+
+static void fe_mul(fe, const fe, const fe);
+static void fe_sq(fe, const fe);
+static void ge_madd(ge_p1p1 *, const ge_p3 *, const ge_precomp *);
+static void ge_msub(ge_p1p1 *, const ge_p3 *, const ge_precomp *);
+static void ge_p2_0(ge_p2 *);
+static void ge_p3_dbl(ge_p1p1 *, const ge_p3 *);
+static void fe_divpowm1(fe, const fe, const fe);
+
+/* Common functions */
+
+uint64_t load_3(const unsigned char *in) {
+  uint64_t result;
+  result = (uint64_t) in[0];
+  result |= ((uint64_t) in[1]) << 8;
+  result |= ((uint64_t) in[2]) << 16;
+  return result;
+}
+
+uint64_t load_4(const unsigned char *in)
+{
+  uint64_t result;
+  result = (uint64_t) in[0];
+  result |= ((uint64_t) in[1]) << 8;
+  result |= ((uint64_t) in[2]) << 16;
+  result |= ((uint64_t) in[3]) << 24;
+  return result;
+}
+
+/* From fe_0.c */
+
+/*
+h = 0
+*/
+
+static void fe_0(fe h) {
+  h[0] = 0;
+  h[1] = 0;
+  h[2] = 0;
+  h[3] = 0;
+  h[4] = 0;
+  h[5] = 0;
+  h[6] = 0;
+  h[7] = 0;
+  h[8] = 0;
+  h[9] = 0;
+}
+
+/* From fe_1.c */
+
+/*
+h = 1
+*/
+
+static void fe_1(fe h) {
+  h[0] = 1;
+  h[1] = 0;
+  h[2] = 0;
+  h[3] = 0;
+  h[4] = 0;
+  h[5] = 0;
+  h[6] = 0;
+  h[7] = 0;
+  h[8] = 0;
+  h[9] = 0;
+}
+
+/* From fe_add.c */
+
+/*
+h = f + g
+Can overlap h with f or g.
+
+Preconditions:
+   |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+   |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+
+Postconditions:
+   |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+void fe_add(fe h, const fe f, const fe g) {
+  int32_t f0 = f[0];
+  int32_t f1 = f[1];
+  int32_t f2 = f[2];
+  int32_t f3 = f[3];
+  int32_t f4 = f[4];
+  int32_t f5 = f[5];
+  int32_t f6 = f[6];
+  int32_t f7 = f[7];
+  int32_t f8 = f[8];
+  int32_t f9 = f[9];
+  int32_t g0 = g[0];
+  int32_t g1 = g[1];
+  int32_t g2 = g[2];
+  int32_t g3 = g[3];
+  int32_t g4 = g[4];
+  int32_t g5 = g[5];
+  int32_t g6 = g[6];
+  int32_t g7 = g[7];
+  int32_t g8 = g[8];
+  int32_t g9 = g[9];
+  int32_t h0 = f0 + g0;
+  int32_t h1 = f1 + g1;
+  int32_t h2 = f2 + g2;
+  int32_t h3 = f3 + g3;
+  int32_t h4 = f4 + g4;
+  int32_t h5 = f5 + g5;
+  int32_t h6 = f6 + g6;
+  int32_t h7 = f7 + g7;
+  int32_t h8 = f8 + g8;
+  int32_t h9 = f9 + g9;
+  h[0] = h0;
+  h[1] = h1;
+  h[2] = h2;
+  h[3] = h3;
+  h[4] = h4;
+  h[5] = h5;
+  h[6] = h6;
+  h[7] = h7;
+  h[8] = h8;
+  h[9] = h9;
+}
+
+/* From fe_cmov.c */
+
+/*
+Replace (f,g) with (g,g) if b == 1;
+replace (f,g) with (f,g) if b == 0.
+
+Preconditions: b in {0,1}.
+*/
+
+static void fe_cmov(fe f, const fe g, unsigned int b) {
+  int32_t f0 = f[0];
+  int32_t f1 = f[1];
+  int32_t f2 = f[2];
+  int32_t f3 = f[3];
+  int32_t f4 = f[4];
+  int32_t f5 = f[5];
+  int32_t f6 = f[6];
+  int32_t f7 = f[7];
+  int32_t f8 = f[8];
+  int32_t f9 = f[9];
+  int32_t g0 = g[0];
+  int32_t g1 = g[1];
+  int32_t g2 = g[2];
+  int32_t g3 = g[3];
+  int32_t g4 = g[4];
+  int32_t g5 = g[5];
+  int32_t g6 = g[6];
+  int32_t g7 = g[7];
+  int32_t g8 = g[8];
+  int32_t g9 = g[9];
+  int32_t x0 = f0 ^ g0;
+  int32_t x1 = f1 ^ g1;
+  int32_t x2 = f2 ^ g2;
+  int32_t x3 = f3 ^ g3;
+  int32_t x4 = f4 ^ g4;
+  int32_t x5 = f5 ^ g5;
+  int32_t x6 = f6 ^ g6;
+  int32_t x7 = f7 ^ g7;
+  int32_t x8 = f8 ^ g8;
+  int32_t x9 = f9 ^ g9;
+  assert((((b - 1) & ~b) | ((b - 2) & ~(b - 1))) == (unsigned int) -1);
+  b = -b;
+  x0 &= b;
+  x1 &= b;
+  x2 &= b;
+  x3 &= b;
+  x4 &= b;
+  x5 &= b;
+  x6 &= b;
+  x7 &= b;
+  x8 &= b;
+  x9 &= b;
+  f[0] = f0 ^ x0;
+  f[1] = f1 ^ x1;
+  f[2] = f2 ^ x2;
+  f[3] = f3 ^ x3;
+  f[4] = f4 ^ x4;
+  f[5] = f5 ^ x5;
+  f[6] = f6 ^ x6;
+  f[7] = f7 ^ x7;
+  f[8] = f8 ^ x8;
+  f[9] = f9 ^ x9;
+}
+
+/* From fe_copy.c */
+
+/*
+h = f
+*/
+
+static void fe_copy(fe h, const fe f) {
+  int32_t f0 = f[0];
+  int32_t f1 = f[1];
+  int32_t f2 = f[2];
+  int32_t f3 = f[3];
+  int32_t f4 = f[4];
+  int32_t f5 = f[5];
+  int32_t f6 = f[6];
+  int32_t f7 = f[7];
+  int32_t f8 = f[8];
+  int32_t f9 = f[9];
+  h[0] = f0;
+  h[1] = f1;
+  h[2] = f2;
+  h[3] = f3;
+  h[4] = f4;
+  h[5] = f5;
+  h[6] = f6;
+  h[7] = f7;
+  h[8] = f8;
+  h[9] = f9;
+}
+
+/* From fe_invert.c */
+
+void fe_invert(fe out, const fe z) {
+  fe t0;
+  fe t1;
+  fe t2;
+  fe t3;
+  int i;
+
+  fe_sq(t0, z);
+  fe_sq(t1, t0);
+  fe_sq(t1, t1);
+  fe_mul(t1, z, t1);
+  fe_mul(t0, t0, t1);
+  fe_sq(t2, t0);
+  fe_mul(t1, t1, t2);
+  fe_sq(t2, t1);
+  for (i = 0; i < 4; ++i) {
+    fe_sq(t2, t2);
+  }
+  fe_mul(t1, t2, t1);
+  fe_sq(t2, t1);
+  for (i = 0; i < 9; ++i) {
+    fe_sq(t2, t2);
+  }
+  fe_mul(t2, t2, t1);
+  fe_sq(t3, t2);
+  for (i = 0; i < 19; ++i) {
+    fe_sq(t3, t3);
+  }
+  fe_mul(t2, t3, t2);
+  fe_sq(t2, t2);
+  for (i = 0; i < 9; ++i) {
+    fe_sq(t2, t2);
+  }
+  fe_mul(t1, t2, t1);
+  fe_sq(t2, t1);
+  for (i = 0; i < 49; ++i) {
+    fe_sq(t2, t2);
+  }
+  fe_mul(t2, t2, t1);
+  fe_sq(t3, t2);
+  for (i = 0; i < 99; ++i) {
+    fe_sq(t3, t3);
+  }
+  fe_mul(t2, t3, t2);
+  fe_sq(t2, t2);
+  for (i = 0; i < 49; ++i) {
+    fe_sq(t2, t2);
+  }
+  fe_mul(t1, t2, t1);
+  fe_sq(t1, t1);
+  for (i = 0; i < 4; ++i) {
+    fe_sq(t1, t1);
+  }
+  fe_mul(out, t1, t0);
+
+  return;
+}
+
+/* From fe_isnegative.c */
+
+/*
+return 1 if f is in {1,3,5,...,q-2}
+return 0 if f is in {0,2,4,...,q-1}
+
+Preconditions:
+   |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+static int fe_isnegative(const fe f) {
+  unsigned char s[32];
+  fe_tobytes(s, f);
+  return s[0] & 1;
+}
+
+/* From fe_isnonzero.c, modified */
+
+static int fe_isnonzero(const fe f) {
+  unsigned char s[32];
+  fe_tobytes(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;
+}
+
+/* From fe_mul.c */
+
+/*
+h = f * g
+Can overlap h with f or g.
+
+Preconditions:
+   |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+   |g| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+
+Postconditions:
+   |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
+*/
+
+/*
+Notes on implementation strategy:
+
+Using schoolbook multiplication.
+Karatsuba would save a little in some cost models.
+
+Most multiplications by 2 and 19 are 32-bit precomputations;
+cheaper than 64-bit postcomputations.
+
+There is one remaining multiplication by 19 in the carry chain;
+one *19 precomputation can be merged into this,
+but the resulting data flow is considerably less clean.
+
+There are 12 carries below.
+10 of them are 2-way parallelizable and vectorizable.
+Can get away with 11 carries, but then data flow is much deeper.
+
+With tighter constraints on inputs can squeeze carries into int32.
+*/
+
+static void fe_mul(fe h, const fe f, const fe g) {
+  int32_t f0 = f[0];
+  int32_t f1 = f[1];
+  int32_t f2 = f[2];
+  int32_t f3 = f[3];
+  int32_t f4 = f[4];
+  int32_t f5 = f[5];
+  int32_t f6 = f[6];
+  int32_t f7 = f[7];
+  int32_t f8 = f[8];
+  int32_t f9 = f[9];
+  int32_t g0 = g[0];
+  int32_t g1 = g[1];
+  int32_t g2 = g[2];
+  int32_t g3 = g[3];
+  int32_t g4 = g[4];
+  int32_t g5 = g[5];
+  int32_t g6 = g[6];
+  int32_t g7 = g[7];
+  int32_t g8 = g[8];
+  int32_t g9 = g[9];
+  int32_t g1_19 = 19 * g1; /* 1.959375*2^29 */
+  int32_t g2_19 = 19 * g2; /* 1.959375*2^30; still ok */
+  int32_t g3_19 = 19 * g3;
+  int32_t g4_19 = 19 * g4;
+  int32_t g5_19 = 19 * g5;
+  int32_t g6_19 = 19 * g6;
+  int32_t g7_19 = 19 * g7;
+  int32_t g8_19 = 19 * g8;
+  int32_t g9_19 = 19 * g9;
+  int32_t f1_2 = 2 * f1;
+  int32_t f3_2 = 2 * f3;
+  int32_t f5_2 = 2 * f5;
+  int32_t f7_2 = 2 * f7;
+  int32_t f9_2 = 2 * f9;
+  int64_t f0g0    = f0   * (int64_t) g0;
+  int64_t f0g1    = f0   * (int64_t) g1;
+  int64_t f0g2    = f0   * (int64_t) g2;
+  int64_t f0g3    = f0   * (int64_t) g3;
+  int64_t f0g4    = f0   * (int64_t) g4;
+  int64_t f0g5    = f0   * (int64_t) g5;
+  int64_t f0g6    = f0   * (int64_t) g6;
+  int64_t f0g7    = f0   * (int64_t) g7;
+  int64_t f0g8    = f0   * (int64_t) g8;
+  int64_t f0g9    = f0   * (int64_t) g9;
+  int64_t f1g0    = f1   * (int64_t) g0;
+  int64_t f1g1_2  = f1_2 * (int64_t) g1;
+  int64_t f1g2    = f1   * (int64_t) g2;
+  int64_t f1g3_2  = f1_2 * (int64_t) g3;
+  int64_t f1g4    = f1   * (int64_t) g4;
+  int64_t f1g5_2  = f1_2 * (int64_t) g5;
+  int64_t f1g6    = f1   * (int64_t) g6;
+  int64_t f1g7_2  = f1_2 * (int64_t) g7;
+  int64_t f1g8    = f1   * (int64_t) g8;
+  int64_t f1g9_38 = f1_2 * (int64_t) g9_19;
+  int64_t f2g0    = f2   * (int64_t) g0;
+  int64_t f2g1    = f2   * (int64_t) g1;
+  int64_t f2g2    = f2   * (int64_t) g2;
+  int64_t f2g3    = f2   * (int64_t) g3;
+  int64_t f2g4    = f2   * (int64_t) g4;
+  int64_t f2g5    = f2   * (int64_t) g5;
+  int64_t f2g6    = f2   * (int64_t) g6;
+  int64_t f2g7    = f2   * (int64_t) g7;
+  int64_t f2g8_19 = f2   * (int64_t) g8_19;
+  int64_t f2g9_19 = f2   * (int64_t) g9_19;
+  int64_t f3g0    = f3   * (int64_t) g0;
+  int64_t f3g1_2  = f3_2 * (int64_t) g1;
+  int64_t f3g2    = f3   * (int64_t) g2;
+  int64_t f3g3_2  = f3_2 * (int64_t) g3;
+  int64_t f3g4    = f3   * (int64_t) g4;
+  int64_t f3g5_2  = f3_2 * (int64_t) g5;
+  int64_t f3g6    = f3   * (int64_t) g6;
+  int64_t f3g7_38 = f3_2 * (int64_t) g7_19;
+  int64_t f3g8_19 = f3   * (int64_t) g8_19;
+  int64_t f3g9_38 = f3_2 * (int64_t) g9_19;
+  int64_t f4g0    = f4   * (int64_t) g0;
+  int64_t f4g1    = f4   * (int64_t) g1;
+  int64_t f4g2    = f4   * (int64_t) g2;
+  int64_t f4g3    = f4   * (int64_t) g3;
+  int64_t f4g4    = f4   * (int64_t) g4;
+  int64_t f4g5    = f4   * (int64_t) g5;
+  int64_t f4g6_19 = f4   * (int64_t) g6_19;
+  int64_t f4g7_19 = f4   * (int64_t) g7_19;
+  int64_t f4g8_19 = f4   * (int64_t) g8_19;
+  int64_t f4g9_19 = f4   * (int64_t) g9_19;
+  int64_t f5g0    = f5   * (int64_t) g0;
+  int64_t f5g1_2  = f5_2 * (int64_t) g1;
+  int64_t f5g2    = f5   * (int64_t) g2;
+  int64_t f5g3_2  = f5_2 * (int64_t) g3;
+  int64_t f5g4    = f5   * (int64_t) g4;
+  int64_t f5g5_38 = f5_2 * (int64_t) g5_19;
+  int64_t f5g6_19 = f5   * (int64_t) g6_19;
+  int64_t f5g7_38 = f5_2 * (int64_t) g7_19;
+  int64_t f5g8_19 = f5   * (int64_t) g8_19;
+  int64_t f5g9_38 = f5_2 * (int64_t) g9_19;
+  int64_t f6g0    = f6   * (int64_t) g0;
+  int64_t f6g1    = f6   * (int64_t) g1;
+  int64_t f6g2    = f6   * (int64_t) g2;
+  int64_t f6g3    = f6   * (int64_t) g3;
+  int64_t f6g4_19 = f6   * (int64_t) g4_19;
+  int64_t f6g5_19 = f6   * (int64_t) g5_19;
+  int64_t f6g6_19 = f6   * (int64_t) g6_19;
+  int64_t f6g7_19 = f6   * (int64_t) g7_19;
+  int64_t f6g8_19 = f6   * (int64_t) g8_19;
+  int64_t f6g9_19 = f6   * (int64_t) g9_19;
+  int64_t f7g0    = f7   * (int64_t) g0;
+  int64_t f7g1_2  = f7_2 * (int64_t) g1;
+  int64_t f7g2    = f7   * (int64_t) g2;
+  int64_t f7g3_38 = f7_2 * (int64_t) g3_19;
+  int64_t f7g4_19 = f7   * (int64_t) g4_19;
+  int64_t f7g5_38 = f7_2 * (int64_t) g5_19;
+  int64_t f7g6_19 = f7   * (int64_t) g6_19;
+  int64_t f7g7_38 = f7_2 * (int64_t) g7_19;
+  int64_t f7g8_19 = f7   * (int64_t) g8_19;
+  int64_t f7g9_38 = f7_2 * (int64_t) g9_19;
+  int64_t f8g0    = f8   * (int64_t) g0;
+  int64_t f8g1    = f8   * (int64_t) g1;
+  int64_t f8g2_19 = f8   * (int64_t) g2_19;
+  int64_t f8g3_19 = f8   * (int64_t) g3_19;
+  int64_t f8g4_19 = f8   * (int64_t) g4_19;
+  int64_t f8g5_19 = f8   * (int64_t) g5_19;
+  int64_t f8g6_19 = f8   * (int64_t) g6_19;
+  int64_t f8g7_19 = f8   * (int64_t) g7_19;
+  int64_t f8g8_19 = f8   * (int64_t) g8_19;
+  int64_t f8g9_19 = f8   * (int64_t) g9_19;
+  int64_t f9g0    = f9   * (int64_t) g0;
+  int64_t f9g1_38 = f9_2 * (int64_t) g1_19;
+  int64_t f9g2_19 = f9   * (int64_t) g2_19;
+  int64_t f9g3_38 = f9_2 * (int64_t) g3_19;
+  int64_t f9g4_19 = f9   * (int64_t) g4_19;
+  int64_t f9g5_38 = f9_2 * (int64_t) g5_19;
+  int64_t f9g6_19 = f9   * (int64_t) g6_19;
+  int64_t f9g7_38 = f9_2 * (int64_t) g7_19;
+  int64_t f9g8_19 = f9   * (int64_t) g8_19;
+  int64_t f9g9_38 = f9_2 * (int64_t) g9_19;
+  int64_t h0 = f0g0+f1g9_38+f2g8_19+f3g7_38+f4g6_19+f5g5_38+f6g4_19+f7g3_38+f8g2_19+f9g1_38;
+  int64_t h1 = f0g1+f1g0   +f2g9_19+f3g8_19+f4g7_19+f5g6_19+f6g5_19+f7g4_19+f8g3_19+f9g2_19;
+  int64_t h2 = f0g2+f1g1_2 +f2g0   +f3g9_38+f4g8_19+f5g7_38+f6g6_19+f7g5_38+f8g4_19+f9g3_38;
+  int64_t h3 = f0g3+f1g2   +f2g1   +f3g0   +f4g9_19+f5g8_19+f6g7_19+f7g6_19+f8g5_19+f9g4_19;
+  int64_t h4 = f0g4+f1g3_2 +f2g2   +f3g1_2 +f4g0   +f5g9_38+f6g8_19+f7g7_38+f8g6_19+f9g5_38;
+  int64_t h5 = f0g5+f1g4   +f2g3   +f3g2   +f4g1   +f5g0   +f6g9_19+f7g8_19+f8g7_19+f9g6_19;
+  int64_t h6 = f0g6+f1g5_2 +f2g4   +f3g3_2 +f4g2   +f5g1_2 +f6g0   +f7g9_38+f8g8_19+f9g7_38;
+  int64_t h7 = f0g7+f1g6   +f2g5   +f3g4   +f4g3   +f5g2   +f6g1   +f7g0   +f8g9_19+f9g8_19;
+  int64_t h8 = f0g8+f1g7_2 +f2g6   +f3g5_2 +f4g4   +f5g3_2 +f6g2   +f7g1_2 +f8g0   +f9g9_38;
+  int64_t h9 = f0g9+f1g8   +f2g7   +f3g6   +f4g5   +f5g4   +f6g3   +f7g2   +f8g1   +f9g0   ;
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+
+  /*
+  |h0| <= (1.65*1.65*2^52*(1+19+19+19+19)+1.65*1.65*2^50*(38+38+38+38+38))
+    i.e. |h0| <= 1.4*2^60; narrower ranges for h2, h4, h6, h8
+  |h1| <= (1.65*1.65*2^51*(1+1+19+19+19+19+19+19+19+19))
+    i.e. |h1| <= 1.7*2^59; narrower ranges for h3, h5, h7, h9
+  */
+
+  carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+  carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+  /* |h0| <= 2^25 */
+  /* |h4| <= 2^25 */
+  /* |h1| <= 1.71*2^59 */
+  /* |h5| <= 1.71*2^59 */
+
+  carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+  carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+  /* |h1| <= 2^24; from now on fits into int32 */
+  /* |h5| <= 2^24; from now on fits into int32 */
+  /* |h2| <= 1.41*2^60 */
+  /* |h6| <= 1.41*2^60 */
+
+  carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+  carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+  /* |h2| <= 2^25; from now on fits into int32 unchanged */
+  /* |h6| <= 2^25; from now on fits into int32 unchanged */
+  /* |h3| <= 1.71*2^59 */
+  /* |h7| <= 1.71*2^59 */
+
+  carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+  carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+  /* |h3| <= 2^24; from now on fits into int32 unchanged */
+  /* |h7| <= 2^24; from now on fits into int32 unchanged */
+  /* |h4| <= 1.72*2^34 */
+  /* |h8| <= 1.41*2^60 */
+
+  carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+  carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+  /* |h4| <= 2^25; from now on fits into int32 unchanged */
+  /* |h8| <= 2^25; from now on fits into int32 unchanged */
+  /* |h5| <= 1.01*2^24 */
+  /* |h9| <= 1.71*2^59 */
+
+  carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+  /* |h9| <= 2^24; from now on fits into int32 unchanged */
+  /* |h0| <= 1.1*2^39 */
+
+  carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+  /* |h0| <= 2^25; from now on fits into int32 unchanged */
+  /* |h1| <= 1.01*2^24 */
+
+  h[0] = h0;
+  h[1] = h1;
+  h[2] = h2;
+  h[3] = h3;
+  h[4] = h4;
+  h[5] = h5;
+  h[6] = h6;
+  h[7] = h7;
+  h[8] = h8;
+  h[9] = h9;
+}
+
+/* From fe_neg.c */
+
+/*
+h = -f
+
+Preconditions:
+   |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+
+Postconditions:
+   |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+*/
+
+static void fe_neg(fe h, const fe f) {
+  int32_t f0 = f[0];
+  int32_t f1 = f[1];
+  int32_t f2 = f[2];
+  int32_t f3 = f[3];
+  int32_t f4 = f[4];
+  int32_t f5 = f[5];
+  int32_t f6 = f[6];
+  int32_t f7 = f[7];
+  int32_t f8 = f[8];
+  int32_t f9 = f[9];
+  int32_t h0 = -f0;
+  int32_t h1 = -f1;
+  int32_t h2 = -f2;
+  int32_t h3 = -f3;
+  int32_t h4 = -f4;
+  int32_t h5 = -f5;
+  int32_t h6 = -f6;
+  int32_t h7 = -f7;
+  int32_t h8 = -f8;
+  int32_t h9 = -f9;
+  h[0] = h0;
+  h[1] = h1;
+  h[2] = h2;
+  h[3] = h3;
+  h[4] = h4;
+  h[5] = h5;
+  h[6] = h6;
+  h[7] = h7;
+  h[8] = h8;
+  h[9] = h9;
+}
+
+/* From fe_sq.c */
+
+/*
+h = f * f
+Can overlap h with f.
+
+Preconditions:
+   |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+
+Postconditions:
+   |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
+*/
+
+/*
+See fe_mul.c for discussion of implementation strategy.
+*/
+
+static void fe_sq(fe h, const fe f) {
+  int32_t f0 = f[0];
+  int32_t f1 = f[1];
+  int32_t f2 = f[2];
+  int32_t f3 = f[3];
+  int32_t f4 = f[4];
+  int32_t f5 = f[5];
+  int32_t f6 = f[6];
+  int32_t f7 = f[7];
+  int32_t f8 = f[8];
+  int32_t f9 = f[9];
+  int32_t f0_2 = 2 * f0;
+  int32_t f1_2 = 2 * f1;
+  int32_t f2_2 = 2 * f2;
+  int32_t f3_2 = 2 * f3;
+  int32_t f4_2 = 2 * f4;
+  int32_t f5_2 = 2 * f5;
+  int32_t f6_2 = 2 * f6;
+  int32_t f7_2 = 2 * f7;
+  int32_t f5_38 = 38 * f5; /* 1.959375*2^30 */
+  int32_t f6_19 = 19 * f6; /* 1.959375*2^30 */
+  int32_t f7_38 = 38 * f7; /* 1.959375*2^30 */
+  int32_t f8_19 = 19 * f8; /* 1.959375*2^30 */
+  int32_t f9_38 = 38 * f9; /* 1.959375*2^30 */
+  int64_t f0f0    = f0   * (int64_t) f0;
+  int64_t f0f1_2  = f0_2 * (int64_t) f1;
+  int64_t f0f2_2  = f0_2 * (int64_t) f2;
+  int64_t f0f3_2  = f0_2 * (int64_t) f3;
+  int64_t f0f4_2  = f0_2 * (int64_t) f4;
+  int64_t f0f5_2  = f0_2 * (int64_t) f5;
+  int64_t f0f6_2  = f0_2 * (int64_t) f6;
+  int64_t f0f7_2  = f0_2 * (int64_t) f7;
+  int64_t f0f8_2  = f0_2 * (int64_t) f8;
+  int64_t f0f9_2  = f0_2 * (int64_t) f9;
+  int64_t f1f1_2  = f1_2 * (int64_t) f1;
+  int64_t f1f2_2  = f1_2 * (int64_t) f2;
+  int64_t f1f3_4  = f1_2 * (int64_t) f3_2;
+  int64_t f1f4_2  = f1_2 * (int64_t) f4;
+  int64_t f1f5_4  = f1_2 * (int64_t) f5_2;
+  int64_t f1f6_2  = f1_2 * (int64_t) f6;
+  int64_t f1f7_4  = f1_2 * (int64_t) f7_2;
+  int64_t f1f8_2  = f1_2 * (int64_t) f8;
+  int64_t f1f9_76 = f1_2 * (int64_t) f9_38;
+  int64_t f2f2    = f2   * (int64_t) f2;
+  int64_t f2f3_2  = f2_2 * (int64_t) f3;
+  int64_t f2f4_2  = f2_2 * (int64_t) f4;
+  int64_t f2f5_2  = f2_2 * (int64_t) f5;
+  int64_t f2f6_2  = f2_2 * (int64_t) f6;
+  int64_t f2f7_2  = f2_2 * (int64_t) f7;
+  int64_t f2f8_38 = f2_2 * (int64_t) f8_19;
+  int64_t f2f9_38 = f2   * (int64_t) f9_38;
+  int64_t f3f3_2  = f3_2 * (int64_t) f3;
+  int64_t f3f4_2  = f3_2 * (int64_t) f4;
+  int64_t f3f5_4  = f3_2 * (int64_t) f5_2;
+  int64_t f3f6_2  = f3_2 * (int64_t) f6;
+  int64_t f3f7_76 = f3_2 * (int64_t) f7_38;
+  int64_t f3f8_38 = f3_2 * (int64_t) f8_19;
+  int64_t f3f9_76 = f3_2 * (int64_t) f9_38;
+  int64_t f4f4    = f4   * (int64_t) f4;
+  int64_t f4f5_2  = f4_2 * (int64_t) f5;
+  int64_t f4f6_38 = f4_2 * (int64_t) f6_19;
+  int64_t f4f7_38 = f4   * (int64_t) f7_38;
+  int64_t f4f8_38 = f4_2 * (int64_t) f8_19;
+  int64_t f4f9_38 = f4   * (int64_t) f9_38;
+  int64_t f5f5_38 = f5   * (int64_t) f5_38;
+  int64_t f5f6_38 = f5_2 * (int64_t) f6_19;
+  int64_t f5f7_76 = f5_2 * (int64_t) f7_38;
+  int64_t f5f8_38 = f5_2 * (int64_t) f8_19;
+  int64_t f5f9_76 = f5_2 * (int64_t) f9_38;
+  int64_t f6f6_19 = f6   * (int64_t) f6_19;
+  int64_t f6f7_38 = f6   * (int64_t) f7_38;
+  int64_t f6f8_38 = f6_2 * (int64_t) f8_19;
+  int64_t f6f9_38 = f6   * (int64_t) f9_38;
+  int64_t f7f7_38 = f7   * (int64_t) f7_38;
+  int64_t f7f8_38 = f7_2 * (int64_t) f8_19;
+  int64_t f7f9_76 = f7_2 * (int64_t) f9_38;
+  int64_t f8f8_19 = f8   * (int64_t) f8_19;
+  int64_t f8f9_38 = f8   * (int64_t) f9_38;
+  int64_t f9f9_38 = f9   * (int64_t) f9_38;
+  int64_t h0 = f0f0  +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38;
+  int64_t h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38;
+  int64_t h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19;
+  int64_t h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38;
+  int64_t h4 = f0f4_2+f1f3_4 +f2f2   +f5f9_76+f6f8_38+f7f7_38;
+  int64_t h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38;
+  int64_t h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19;
+  int64_t h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38;
+  int64_t h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4   +f9f9_38;
+  int64_t h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2;
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+
+  carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+  carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+
+  carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+  carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+
+  carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+  carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+
+  carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+  carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+  carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+  carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+  carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+
+  carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+
+  h[0] = h0;
+  h[1] = h1;
+  h[2] = h2;
+  h[3] = h3;
+  h[4] = h4;
+  h[5] = h5;
+  h[6] = h6;
+  h[7] = h7;
+  h[8] = h8;
+  h[9] = h9;
+}
+
+/* From fe_sq2.c */
+
+/*
+h = 2 * f * f
+Can overlap h with f.
+
+Preconditions:
+   |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+
+Postconditions:
+   |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
+*/
+
+/*
+See fe_mul.c for discussion of implementation strategy.
+*/
+
+static void fe_sq2(fe h, const fe f) {
+  int32_t f0 = f[0];
+  int32_t f1 = f[1];
+  int32_t f2 = f[2];
+  int32_t f3 = f[3];
+  int32_t f4 = f[4];
+  int32_t f5 = f[5];
+  int32_t f6 = f[6];
+  int32_t f7 = f[7];
+  int32_t f8 = f[8];
+  int32_t f9 = f[9];
+  int32_t f0_2 = 2 * f0;
+  int32_t f1_2 = 2 * f1;
+  int32_t f2_2 = 2 * f2;
+  int32_t f3_2 = 2 * f3;
+  int32_t f4_2 = 2 * f4;
+  int32_t f5_2 = 2 * f5;
+  int32_t f6_2 = 2 * f6;
+  int32_t f7_2 = 2 * f7;
+  int32_t f5_38 = 38 * f5; /* 1.959375*2^30 */
+  int32_t f6_19 = 19 * f6; /* 1.959375*2^30 */
+  int32_t f7_38 = 38 * f7; /* 1.959375*2^30 */
+  int32_t f8_19 = 19 * f8; /* 1.959375*2^30 */
+  int32_t f9_38 = 38 * f9; /* 1.959375*2^30 */
+  int64_t f0f0    = f0   * (int64_t) f0;
+  int64_t f0f1_2  = f0_2 * (int64_t) f1;
+  int64_t f0f2_2  = f0_2 * (int64_t) f2;
+  int64_t f0f3_2  = f0_2 * (int64_t) f3;
+  int64_t f0f4_2  = f0_2 * (int64_t) f4;
+  int64_t f0f5_2  = f0_2 * (int64_t) f5;
+  int64_t f0f6_2  = f0_2 * (int64_t) f6;
+  int64_t f0f7_2  = f0_2 * (int64_t) f7;
+  int64_t f0f8_2  = f0_2 * (int64_t) f8;
+  int64_t f0f9_2  = f0_2 * (int64_t) f9;
+  int64_t f1f1_2  = f1_2 * (int64_t) f1;
+  int64_t f1f2_2  = f1_2 * (int64_t) f2;
+  int64_t f1f3_4  = f1_2 * (int64_t) f3_2;
+  int64_t f1f4_2  = f1_2 * (int64_t) f4;
+  int64_t f1f5_4  = f1_2 * (int64_t) f5_2;
+  int64_t f1f6_2  = f1_2 * (int64_t) f6;
+  int64_t f1f7_4  = f1_2 * (int64_t) f7_2;
+  int64_t f1f8_2  = f1_2 * (int64_t) f8;
+  int64_t f1f9_76 = f1_2 * (int64_t) f9_38;
+  int64_t f2f2    = f2   * (int64_t) f2;
+  int64_t f2f3_2  = f2_2 * (int64_t) f3;
+  int64_t f2f4_2  = f2_2 * (int64_t) f4;
+  int64_t f2f5_2  = f2_2 * (int64_t) f5;
+  int64_t f2f6_2  = f2_2 * (int64_t) f6;
+  int64_t f2f7_2  = f2_2 * (int64_t) f7;
+  int64_t f2f8_38 = f2_2 * (int64_t) f8_19;
+  int64_t f2f9_38 = f2   * (int64_t) f9_38;
+  int64_t f3f3_2  = f3_2 * (int64_t) f3;
+  int64_t f3f4_2  = f3_2 * (int64_t) f4;
+  int64_t f3f5_4  = f3_2 * (int64_t) f5_2;
+  int64_t f3f6_2  = f3_2 * (int64_t) f6;
+  int64_t f3f7_76 = f3_2 * (int64_t) f7_38;
+  int64_t f3f8_38 = f3_2 * (int64_t) f8_19;
+  int64_t f3f9_76 = f3_2 * (int64_t) f9_38;
+  int64_t f4f4    = f4   * (int64_t) f4;
+  int64_t f4f5_2  = f4_2 * (int64_t) f5;
+  int64_t f4f6_38 = f4_2 * (int64_t) f6_19;
+  int64_t f4f7_38 = f4   * (int64_t) f7_38;
+  int64_t f4f8_38 = f4_2 * (int64_t) f8_19;
+  int64_t f4f9_38 = f4   * (int64_t) f9_38;
+  int64_t f5f5_38 = f5   * (int64_t) f5_38;
+  int64_t f5f6_38 = f5_2 * (int64_t) f6_19;
+  int64_t f5f7_76 = f5_2 * (int64_t) f7_38;
+  int64_t f5f8_38 = f5_2 * (int64_t) f8_19;
+  int64_t f5f9_76 = f5_2 * (int64_t) f9_38;
+  int64_t f6f6_19 = f6   * (int64_t) f6_19;
+  int64_t f6f7_38 = f6   * (int64_t) f7_38;
+  int64_t f6f8_38 = f6_2 * (int64_t) f8_19;
+  int64_t f6f9_38 = f6   * (int64_t) f9_38;
+  int64_t f7f7_38 = f7   * (int64_t) f7_38;
+  int64_t f7f8_38 = f7_2 * (int64_t) f8_19;
+  int64_t f7f9_76 = f7_2 * (int64_t) f9_38;
+  int64_t f8f8_19 = f8   * (int64_t) f8_19;
+  int64_t f8f9_38 = f8   * (int64_t) f9_38;
+  int64_t f9f9_38 = f9   * (int64_t) f9_38;
+  int64_t h0 = f0f0  +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38;
+  int64_t h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38;
+  int64_t h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19;
+  int64_t h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38;
+  int64_t h4 = f0f4_2+f1f3_4 +f2f2   +f5f9_76+f6f8_38+f7f7_38;
+  int64_t h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38;
+  int64_t h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19;
+  int64_t h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38;
+  int64_t h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4   +f9f9_38;
+  int64_t h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2;
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+
+  h0 += h0;
+  h1 += h1;
+  h2 += h2;
+  h3 += h3;
+  h4 += h4;
+  h5 += h5;
+  h6 += h6;
+  h7 += h7;
+  h8 += h8;
+  h9 += h9;
+
+  carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+  carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+
+  carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+  carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+
+  carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+  carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+
+  carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+  carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+  carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+  carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+  carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+
+  carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+
+  h[0] = h0;
+  h[1] = h1;
+  h[2] = h2;
+  h[3] = h3;
+  h[4] = h4;
+  h[5] = h5;
+  h[6] = h6;
+  h[7] = h7;
+  h[8] = h8;
+  h[9] = h9;
+}
+
+/* From fe_sub.c */
+
+/*
+h = f - g
+Can overlap h with f or g.
+
+Preconditions:
+   |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+   |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+
+Postconditions:
+   |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+static void fe_sub(fe h, const fe f, const fe g) {
+  int32_t f0 = f[0];
+  int32_t f1 = f[1];
+  int32_t f2 = f[2];
+  int32_t f3 = f[3];
+  int32_t f4 = f[4];
+  int32_t f5 = f[5];
+  int32_t f6 = f[6];
+  int32_t f7 = f[7];
+  int32_t f8 = f[8];
+  int32_t f9 = f[9];
+  int32_t g0 = g[0];
+  int32_t g1 = g[1];
+  int32_t g2 = g[2];
+  int32_t g3 = g[3];
+  int32_t g4 = g[4];
+  int32_t g5 = g[5];
+  int32_t g6 = g[6];
+  int32_t g7 = g[7];
+  int32_t g8 = g[8];
+  int32_t g9 = g[9];
+  int32_t h0 = f0 - g0;
+  int32_t h1 = f1 - g1;
+  int32_t h2 = f2 - g2;
+  int32_t h3 = f3 - g3;
+  int32_t h4 = f4 - g4;
+  int32_t h5 = f5 - g5;
+  int32_t h6 = f6 - g6;
+  int32_t h7 = f7 - g7;
+  int32_t h8 = f8 - g8;
+  int32_t h9 = f9 - g9;
+  h[0] = h0;
+  h[1] = h1;
+  h[2] = h2;
+  h[3] = h3;
+  h[4] = h4;
+  h[5] = h5;
+  h[6] = h6;
+  h[7] = h7;
+  h[8] = h8;
+  h[9] = h9;
+}
+
+/* From fe_tobytes.c */
+
+/*
+Preconditions:
+  |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+
+Write p=2^255-19; q=floor(h/p).
+Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))).
+
+Proof:
+  Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4.
+  Also have |h-2^230 h9|<2^231 so |19 2^(-255)(h-2^230 h9)|<1/4.
+
+  Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9).
+  Then 0<y<1.
+
+  Write r=h-pq.
+  Have 0<=r<=p-1=2^255-20.
+  Thus 0<=r+19(2^-255)r<r+19(2^-255)2^255<=2^255-1.
+
+  Write x=r+19(2^-255)r+y.
+  Then 0<x<2^255 so floor(2^(-255)x) = 0 so floor(q+2^(-255)x) = q.
+
+  Have q+2^(-255)x = 2^(-255)(h + 19 2^(-25) h9 + 2^(-1))
+  so floor(2^(-255)(h + 19 2^(-25) h9 + 2^(-1))) = q.
+*/
+
+void fe_tobytes(unsigned char *s, const fe h) {
+  int32_t h0 = h[0];
+  int32_t h1 = h[1];
+  int32_t h2 = h[2];
+  int32_t h3 = h[3];
+  int32_t h4 = h[4];
+  int32_t h5 = h[5];
+  int32_t h6 = h[6];
+  int32_t h7 = h[7];
+  int32_t h8 = h[8];
+  int32_t h9 = h[9];
+  int32_t q;
+  int32_t carry0;
+  int32_t carry1;
+  int32_t carry2;
+  int32_t carry3;
+  int32_t carry4;
+  int32_t carry5;
+  int32_t carry6;
+  int32_t carry7;
+  int32_t carry8;
+  int32_t carry9;
+
+  q = (19 * h9 + (((int32_t) 1) << 24)) >> 25;
+  q = (h0 + q) >> 26;
+  q = (h1 + q) >> 25;
+  q = (h2 + q) >> 26;
+  q = (h3 + q) >> 25;
+  q = (h4 + q) >> 26;
+  q = (h5 + q) >> 25;
+  q = (h6 + q) >> 26;
+  q = (h7 + q) >> 25;
+  q = (h8 + q) >> 26;
+  q = (h9 + q) >> 25;
+
+  /* Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. */
+  h0 += 19 * q;
+  /* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */
+
+  carry0 = h0 >> 26; h1 += carry0; h0 -= carry0 << 26;
+  carry1 = h1 >> 25; h2 += carry1; h1 -= carry1 << 25;
+  carry2 = h2 >> 26; h3 += carry2; h2 -= carry2 << 26;
+  carry3 = h3 >> 25; h4 += carry3; h3 -= carry3 << 25;
+  carry4 = h4 >> 26; h5 += carry4; h4 -= carry4 << 26;
+  carry5 = h5 >> 25; h6 += carry5; h5 -= carry5 << 25;
+  carry6 = h6 >> 26; h7 += carry6; h6 -= carry6 << 26;
+  carry7 = h7 >> 25; h8 += carry7; h7 -= carry7 << 25;
+  carry8 = h8 >> 26; h9 += carry8; h8 -= carry8 << 26;
+  carry9 = h9 >> 25;               h9 -= carry9 << 25;
+                  /* h10 = carry9 */
+
+  /*
+  Goal: Output h0+...+2^255 h10-2^255 q, which is between 0 and 2^255-20.
+  Have h0+...+2^230 h9 between 0 and 2^255-1;
+  evidently 2^255 h10-2^255 q = 0.
+  Goal: Output h0+...+2^230 h9.
+  */
+
+  s[0] = h0 >> 0;
+  s[1] = h0 >> 8;
+  s[2] = h0 >> 16;
+  s[3] = (h0 >> 24) | (h1 << 2);
+  s[4] = h1 >> 6;
+  s[5] = h1 >> 14;
+  s[6] = (h1 >> 22) | (h2 << 3);
+  s[7] = h2 >> 5;
+  s[8] = h2 >> 13;
+  s[9] = (h2 >> 21) | (h3 << 5);
+  s[10] = h3 >> 3;
+  s[11] = h3 >> 11;
+  s[12] = (h3 >> 19) | (h4 << 6);
+  s[13] = h4 >> 2;
+  s[14] = h4 >> 10;
+  s[15] = h4 >> 18;
+  s[16] = h5 >> 0;
+  s[17] = h5 >> 8;
+  s[18] = h5 >> 16;
+  s[19] = (h5 >> 24) | (h6 << 1);
+  s[20] = h6 >> 7;
+  s[21] = h6 >> 15;
+  s[22] = (h6 >> 23) | (h7 << 3);
+  s[23] = h7 >> 5;
+  s[24] = h7 >> 13;
+  s[25] = (h7 >> 21) | (h8 << 4);
+  s[26] = h8 >> 4;
+  s[27] = h8 >> 12;
+  s[28] = (h8 >> 20) | (h9 << 6);
+  s[29] = h9 >> 2;
+  s[30] = h9 >> 10;
+  s[31] = h9 >> 18;
+}
+
+/* From ge_add.c */
+
+void ge_add(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) {
+  fe t0;
+  fe_add(r->X, p->Y, p->X);
+  fe_sub(r->Y, p->Y, p->X);
+  fe_mul(r->Z, r->X, q->YplusX);
+  fe_mul(r->Y, r->Y, q->YminusX);
+  fe_mul(r->T, q->T2d, p->T);
+  fe_mul(r->X, p->Z, q->Z);
+  fe_add(t0, r->X, r->X);
+  fe_sub(r->X, r->Z, r->Y);
+  fe_add(r->Y, r->Z, r->Y);
+  fe_add(r->Z, t0, r->T);
+  fe_sub(r->T, t0, r->T);
+}
+
+/* From ge_double_scalarmult.c, modified */
+
+static void slide(signed char *r, const unsigned char *a) {
+  int i;
+  int b;
+  int k;
+
+  for (i = 0; i < 256; ++i) {
+    r[i] = 1 & (a[i >> 3] >> (i & 7));
+  }
+
+  for (i = 0; i < 256; ++i) {
+    if (r[i]) {
+      for (b = 1; b <= 6 && i + b < 256; ++b) {
+        if (r[i + b]) {
+          if (r[i] + (r[i + b] << b) <= 15) {
+            r[i] += r[i + b] << b; r[i + b] = 0;
+          } else if (r[i] - (r[i + b] << b) >= -15) {
+            r[i] -= r[i + b] << b;
+            for (k = i + b; k < 256; ++k) {
+              if (!r[k]) {
+                r[k] = 1;
+                break;
+              }
+              r[k] = 0;
+            }
+          } else
+            break;
+        }
+      }
+    }
+  }
+}
+
+void ge_dsm_precomp(ge_dsmp r, const ge_p3 *s) {
+  ge_p1p1 t;
+  ge_p3 s2, u;
+  ge_p3_to_cached(&r[0], s);
+  ge_p3_dbl(&t, s); ge_p1p1_to_p3(&s2, &t);
+  ge_add(&t, &s2, &r[0]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&r[1], &u);
+  ge_add(&t, &s2, &r[1]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&r[2], &u);
+  ge_add(&t, &s2, &r[2]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&r[3], &u);
+  ge_add(&t, &s2, &r[3]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&r[4], &u);
+  ge_add(&t, &s2, &r[4]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&r[5], &u);
+  ge_add(&t, &s2, &r[5]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&r[6], &u);
+  ge_add(&t, &s2, &r[6]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&r[7], &u);
+}
+
+/*
+r = a * A + b * B
+where a = a[0]+256*a[1]+...+256^31 a[31].
+and b = b[0]+256*b[1]+...+256^31 b[31].
+B is the Ed25519 base point (x,4/5) with x positive.
+*/
+
+void ge_double_scalarmult_base_vartime(ge_p2 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b) {
+  signed char aslide[256];
+  signed char bslide[256];
+  ge_dsmp Ai; /* A, 3A, 5A, 7A, 9A, 11A, 13A, 15A */
+  ge_p1p1 t;
+  ge_p3 u;
+  int i;
+
+  slide(aslide, a);
+  slide(bslide, b);
+  ge_dsm_precomp(Ai, A);
+
+  ge_p2_0(r);
+
+  for (i = 255; i >= 0; --i) {
+    if (aslide[i] || bslide[i]) break;
+  }
+
+  for (; i >= 0; --i) {
+    ge_p2_dbl(&t, r);
+
+    if (aslide[i] > 0) {
+      ge_p1p1_to_p3(&u, &t);
+      ge_add(&t, &u, &Ai[aslide[i]/2]);
+    } else if (aslide[i] < 0) {
+      ge_p1p1_to_p3(&u, &t);
+      ge_sub(&t, &u, &Ai[(-aslide[i])/2]);
+    }
+
+    if (bslide[i] > 0) {
+      ge_p1p1_to_p3(&u, &t);
+      ge_madd(&t, &u, &ge_Bi[bslide[i]/2]);
+    } else if (bslide[i] < 0) {
+      ge_p1p1_to_p3(&u, &t);
+      ge_msub(&t, &u, &ge_Bi[(-bslide[i])/2]);
+    }
+
+    ge_p1p1_to_p2(r, &t);
+  }
+}
+
+/* From ge_frombytes.c, modified */
+
+int ge_frombytes_vartime(ge_p3 *h, const unsigned char *s) {
+  fe u;
+  fe v;
+  fe vxx;
+  fe check;
+
+  /* From fe_frombytes.c */
+
+  int64_t h0 = load_4(s);
+  int64_t h1 = load_3(s + 4) << 6;
+  int64_t h2 = load_3(s + 7) << 5;
+  int64_t h3 = load_3(s + 10) << 3;
+  int64_t h4 = load_3(s + 13) << 2;
+  int64_t h5 = load_4(s + 16);
+  int64_t h6 = load_3(s + 20) << 7;
+  int64_t h7 = load_3(s + 23) << 5;
+  int64_t h8 = load_3(s + 26) << 4;
+  int64_t h9 = (load_3(s + 29) & 8388607) << 2;
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+
+  /* Validate the number to be canonical */
+  if (h9 == 33554428 && h8 == 268435440 && h7 == 536870880 && h6 == 2147483520 &&
+    h5 == 4294967295 && h4 == 67108860 && h3 == 134217720 && h2 == 536870880 &&
+    h1 == 1073741760 && h0 >= 4294967277) {
+    return -1;
+  }
+
+  carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+  carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+  carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+  carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+  carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+  carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+  carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+  carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+  carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+  carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+  h->Y[0] = h0;
+  h->Y[1] = h1;
+  h->Y[2] = h2;
+  h->Y[3] = h3;
+  h->Y[4] = h4;
+  h->Y[5] = h5;
+  h->Y[6] = h6;
+  h->Y[7] = h7;
+  h->Y[8] = h8;
+  h->Y[9] = h9;
+
+  /* End fe_frombytes.c */
+
+  fe_1(h->Z);
+  fe_sq(u, h->Y);
+  fe_mul(v, u, fe_d);
+  fe_sub(u, u, h->Z);       /* u = y^2-1 */
+  fe_add(v, v, h->Z);       /* v = dy^2+1 */
+
+  fe_divpowm1(h->X, u, v); /* x = uv^3(uv^7)^((q-5)/8) */
+
+  fe_sq(vxx, h->X);
+  fe_mul(vxx, vxx, v);
+  fe_sub(check, vxx, u);    /* vx^2-u */
+  if (fe_isnonzero(check)) {
+    fe_add(check, vxx, u);  /* vx^2+u */
+    if (fe_isnonzero(check)) {
+      return -1;
+    }
+    fe_mul(h->X, h->X, fe_sqrtm1);
+  }
+
+  if (fe_isnegative(h->X) != (s[31] >> 7)) {
+    /* If x = 0, the sign must be positive */
+    if (!fe_isnonzero(h->X)) {
+      return -1;
+    }
+    fe_neg(h->X, h->X);
+  }
+
+  fe_mul(h->T, h->X, h->Y);
+  return 0;
+}
+
+/* From ge_madd.c */
+
+/*
+r = p + q
+*/
+
+static void ge_madd(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) {
+  fe t0;
+  fe_add(r->X, p->Y, p->X);
+  fe_sub(r->Y, p->Y, p->X);
+  fe_mul(r->Z, r->X, q->yplusx);
+  fe_mul(r->Y, r->Y, q->yminusx);
+  fe_mul(r->T, q->xy2d, p->T);
+  fe_add(t0, p->Z, p->Z);
+  fe_sub(r->X, r->Z, r->Y);
+  fe_add(r->Y, r->Z, r->Y);
+  fe_add(r->Z, t0, r->T);
+  fe_sub(r->T, t0, r->T);
+}
+
+/* From ge_msub.c */
+
+/*
+r = p - q
+*/
+
+static void ge_msub(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) {
+  fe t0;
+  fe_add(r->X, p->Y, p->X);
+  fe_sub(r->Y, p->Y, p->X);
+  fe_mul(r->Z, r->X, q->yminusx);
+  fe_mul(r->Y, r->Y, q->yplusx);
+  fe_mul(r->T, q->xy2d, p->T);
+  fe_add(t0, p->Z, p->Z);
+  fe_sub(r->X, r->Z, r->Y);
+  fe_add(r->Y, r->Z, r->Y);
+  fe_sub(r->Z, t0, r->T);
+  fe_add(r->T, t0, r->T);
+}
+
+/* From ge_p1p1_to_p2.c */
+
+/*
+r = p
+*/
+
+void ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p) {
+  fe_mul(r->X, p->X, p->T);
+  fe_mul(r->Y, p->Y, p->Z);
+  fe_mul(r->Z, p->Z, p->T);
+}
+
+/* From ge_p1p1_to_p3.c */
+
+/*
+r = p
+*/
+
+void ge_p1p1_to_p3(ge_p3 *r, const ge_p1p1 *p) {
+  fe_mul(r->X, p->X, p->T);
+  fe_mul(r->Y, p->Y, p->Z);
+  fe_mul(r->Z, p->Z, p->T);
+  fe_mul(r->T, p->X, p->Y);
+}
+
+/* From ge_p2_0.c */
+
+static void ge_p2_0(ge_p2 *h) {
+  fe_0(h->X);
+  fe_1(h->Y);
+  fe_1(h->Z);
+}
+
+/* From ge_p2_dbl.c */
+
+/*
+r = 2 * p
+*/
+
+void ge_p2_dbl(ge_p1p1 *r, const ge_p2 *p) {
+  fe t0;
+  fe_sq(r->X, p->X);
+  fe_sq(r->Z, p->Y);
+  fe_sq2(r->T, p->Z);
+  fe_add(r->Y, p->X, p->Y);
+  fe_sq(t0, r->Y);
+  fe_add(r->Y, r->Z, r->X);
+  fe_sub(r->Z, r->Z, r->X);
+  fe_sub(r->X, t0, r->Y);
+  fe_sub(r->T, r->T, r->Z);
+}
+
+/* From ge_p3_0.c */
+
+static void ge_p3_0(ge_p3 *h) {
+  fe_0(h->X);
+  fe_1(h->Y);
+  fe_1(h->Z);
+  fe_0(h->T);
+}
+
+/* From ge_p3_dbl.c */
+
+/*
+r = 2 * p
+*/
+
+static void ge_p3_dbl(ge_p1p1 *r, const ge_p3 *p) {
+  ge_p2 q;
+  ge_p3_to_p2(&q, p);
+  ge_p2_dbl(r, &q);
+}
+
+/* From ge_p3_to_cached.c */
+
+/*
+r = p
+*/
+
+void ge_p3_to_cached(ge_cached *r, const ge_p3 *p) {
+  fe_add(r->YplusX, p->Y, p->X);
+  fe_sub(r->YminusX, p->Y, p->X);
+  fe_copy(r->Z, p->Z);
+  fe_mul(r->T2d, p->T, fe_d2);
+}
+
+/* From ge_p3_to_p2.c */
+
+/*
+r = p
+*/
+
+void ge_p3_to_p2(ge_p2 *r, const ge_p3 *p) {
+  fe_copy(r->X, p->X);
+  fe_copy(r->Y, p->Y);
+  fe_copy(r->Z, p->Z);
+}
+
+/* From ge_p3_tobytes.c */
+
+void ge_p3_tobytes(unsigned char *s, const ge_p3 *h) {
+  fe recip;
+  fe x;
+  fe y;
+
+  fe_invert(recip, h->Z);
+  fe_mul(x, h->X, recip);
+  fe_mul(y, h->Y, recip);
+  fe_tobytes(s, y);
+  s[31] ^= fe_isnegative(x) << 7;
+}
+
+/* From ge_precomp_0.c */
+
+static void ge_precomp_0(ge_precomp *h) {
+  fe_1(h->yplusx);
+  fe_1(h->yminusx);
+  fe_0(h->xy2d);
+}
+
+/* From ge_scalarmult_base.c */
+
+static unsigned char equal(signed char b, signed char c) {
+  unsigned char ub = b;
+  unsigned char uc = c;
+  unsigned char x = ub ^ uc; /* 0: yes; 1..255: no */
+  uint32_t y = x; /* 0: yes; 1..255: no */
+  y -= 1; /* 4294967295: yes; 0..254: no */
+  y >>= 31; /* 1: yes; 0: no */
+  return y;
+}
+
+static unsigned char negative(signed char b) {
+  unsigned long long x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */
+  x >>= 63; /* 1: yes; 0: no */
+  return x;
+}
+
+static void ge_precomp_cmov(ge_precomp *t, const ge_precomp *u, unsigned char b) {
+  fe_cmov(t->yplusx, u->yplusx, b);
+  fe_cmov(t->yminusx, u->yminusx, b);
+  fe_cmov(t->xy2d, u->xy2d, b);
+}
+
+static void select(ge_precomp *t, int pos, signed char b) {
+  ge_precomp minust;
+  unsigned char bnegative = negative(b);
+  unsigned char babs = b - (((-bnegative) & b) << 1);
+
+  ge_precomp_0(t);
+  ge_precomp_cmov(t, &ge_base[pos][0], equal(babs, 1));
+  ge_precomp_cmov(t, &ge_base[pos][1], equal(babs, 2));
+  ge_precomp_cmov(t, &ge_base[pos][2], equal(babs, 3));
+  ge_precomp_cmov(t, &ge_base[pos][3], equal(babs, 4));
+  ge_precomp_cmov(t, &ge_base[pos][4], equal(babs, 5));
+  ge_precomp_cmov(t, &ge_base[pos][5], equal(babs, 6));
+  ge_precomp_cmov(t, &ge_base[pos][6], equal(babs, 7));
+  ge_precomp_cmov(t, &ge_base[pos][7], equal(babs, 8));
+  fe_copy(minust.yplusx, t->yminusx);
+  fe_copy(minust.yminusx, t->yplusx);
+  fe_neg(minust.xy2d, t->xy2d);
+  ge_precomp_cmov(t, &minust, bnegative);
+}
+
+/*
+h = a * B
+where a = a[0]+256*a[1]+...+256^31 a[31]
+B is the Ed25519 base point (x,4/5) with x positive.
+
+Preconditions:
+  a[31] <= 127
+*/
+
+void ge_scalarmult_base(ge_p3 *h, const unsigned char *a) {
+  signed char e[64];
+  signed char carry;
+  ge_p1p1 r;
+  ge_p2 s;
+  ge_precomp t;
+  int i;
+
+  for (i = 0; i < 32; ++i) {
+    e[2 * i + 0] = (a[i] >> 0) & 15;
+    e[2 * i + 1] = (a[i] >> 4) & 15;
+  }
+  /* each e[i] is between 0 and 15 */
+  /* e[63] is between 0 and 7 */
+
+  carry = 0;
+  for (i = 0; i < 63; ++i) {
+    e[i] += carry;
+    carry = e[i] + 8;
+    carry >>= 4;
+    e[i] -= carry << 4;
+  }
+  e[63] += carry;
+  /* each e[i] is between -8 and 8 */
+
+  ge_p3_0(h);
+  for (i = 1; i < 64; i += 2) {
+    select(&t, i / 2, e[i]);
+    ge_madd(&r, h, &t); ge_p1p1_to_p3(h, &r);
+  }
+
+  ge_p3_dbl(&r, h);  ge_p1p1_to_p2(&s, &r);
+  ge_p2_dbl(&r, &s); ge_p1p1_to_p2(&s, &r);
+  ge_p2_dbl(&r, &s); ge_p1p1_to_p2(&s, &r);
+  ge_p2_dbl(&r, &s); ge_p1p1_to_p3(h, &r);
+
+  for (i = 0; i < 64; i += 2) {
+    select(&t, i / 2, e[i]);
+    ge_madd(&r, h, &t); ge_p1p1_to_p3(h, &r);
+  }
+}
+
+/* From ge_sub.c */
+
+/*
+r = p - q
+*/
+
+void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) {
+  fe t0;
+  fe_add(r->X, p->Y, p->X);
+  fe_sub(r->Y, p->Y, p->X);
+  fe_mul(r->Z, r->X, q->YminusX);
+  fe_mul(r->Y, r->Y, q->YplusX);
+  fe_mul(r->T, q->T2d, p->T);
+  fe_mul(r->X, p->Z, q->Z);
+  fe_add(t0, r->X, r->X);
+  fe_sub(r->X, r->Z, r->Y);
+  fe_add(r->Y, r->Z, r->Y);
+  fe_sub(r->Z, t0, r->T);
+  fe_add(r->T, t0, r->T);
+}
+
+/* From ge_tobytes.c */
+
+void ge_tobytes(unsigned char *s, const ge_p2 *h) {
+  fe recip;
+  fe x;
+  fe y;
+
+  fe_invert(recip, h->Z);
+  fe_mul(x, h->X, recip);
+  fe_mul(y, h->Y, recip);
+  fe_tobytes(s, y);
+  s[31] ^= fe_isnegative(x) << 7;
+}
+
+/* From sc_reduce.c */
+
+/*
+Input:
+  s[0]+256*s[1]+...+256^63*s[63] = s
+
+Output:
+  s[0]+256*s[1]+...+256^31*s[31] = s mod l
+  where l = 2^252 + 27742317777372353535851937790883648493.
+  Overwrites s in place.
+*/
+
+void sc_reduce(unsigned char *s) {
+  int64_t s0 = 2097151 & load_3(s);
+  int64_t s1 = 2097151 & (load_4(s + 2) >> 5);
+  int64_t s2 = 2097151 & (load_3(s + 5) >> 2);
+  int64_t s3 = 2097151 & (load_4(s + 7) >> 7);
+  int64_t s4 = 2097151 & (load_4(s + 10) >> 4);
+  int64_t s5 = 2097151 & (load_3(s + 13) >> 1);
+  int64_t s6 = 2097151 & (load_4(s + 15) >> 6);
+  int64_t s7 = 2097151 & (load_3(s + 18) >> 3);
+  int64_t s8 = 2097151 & load_3(s + 21);
+  int64_t s9 = 2097151 & (load_4(s + 23) >> 5);
+  int64_t s10 = 2097151 & (load_3(s + 26) >> 2);
+  int64_t s11 = 2097151 & (load_4(s + 28) >> 7);
+  int64_t s12 = 2097151 & (load_4(s + 31) >> 4);
+  int64_t s13 = 2097151 & (load_3(s + 34) >> 1);
+  int64_t s14 = 2097151 & (load_4(s + 36) >> 6);
+  int64_t s15 = 2097151 & (load_3(s + 39) >> 3);
+  int64_t s16 = 2097151 & load_3(s + 42);
+  int64_t s17 = 2097151 & (load_4(s + 44) >> 5);
+  int64_t s18 = 2097151 & (load_3(s + 47) >> 2);
+  int64_t s19 = 2097151 & (load_4(s + 49) >> 7);
+  int64_t s20 = 2097151 & (load_4(s + 52) >> 4);
+  int64_t s21 = 2097151 & (load_3(s + 55) >> 1);
+  int64_t s22 = 2097151 & (load_4(s + 57) >> 6);
+  int64_t s23 = (load_4(s + 60) >> 3);
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+  int64_t carry10;
+  int64_t carry11;
+  int64_t carry12;
+  int64_t carry13;
+  int64_t carry14;
+  int64_t carry15;
+  int64_t carry16;
+
+  s11 += s23 * 666643;
+  s12 += s23 * 470296;
+  s13 += s23 * 654183;
+  s14 -= s23 * 997805;
+  s15 += s23 * 136657;
+  s16 -= s23 * 683901;
+
+  s10 += s22 * 666643;
+  s11 += s22 * 470296;
+  s12 += s22 * 654183;
+  s13 -= s22 * 997805;
+  s14 += s22 * 136657;
+  s15 -= s22 * 683901;
+
+  s9 += s21 * 666643;
+  s10 += s21 * 470296;
+  s11 += s21 * 654183;
+  s12 -= s21 * 997805;
+  s13 += s21 * 136657;
+  s14 -= s21 * 683901;
+
+  s8 += s20 * 666643;
+  s9 += s20 * 470296;
+  s10 += s20 * 654183;
+  s11 -= s20 * 997805;
+  s12 += s20 * 136657;
+  s13 -= s20 * 683901;
+
+  s7 += s19 * 666643;
+  s8 += s19 * 470296;
+  s9 += s19 * 654183;
+  s10 -= s19 * 997805;
+  s11 += s19 * 136657;
+  s12 -= s19 * 683901;
+
+  s6 += s18 * 666643;
+  s7 += s18 * 470296;
+  s8 += s18 * 654183;
+  s9 -= s18 * 997805;
+  s10 += s18 * 136657;
+  s11 -= s18 * 683901;
+
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
+  carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
+  carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
+
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+  carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
+  carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
+
+  s5 += s17 * 666643;
+  s6 += s17 * 470296;
+  s7 += s17 * 654183;
+  s8 -= s17 * 997805;
+  s9 += s17 * 136657;
+  s10 -= s17 * 683901;
+
+  s4 += s16 * 666643;
+  s5 += s16 * 470296;
+  s6 += s16 * 654183;
+  s7 -= s16 * 997805;
+  s8 += s16 * 136657;
+  s9 -= s16 * 683901;
+
+  s3 += s15 * 666643;
+  s4 += s15 * 470296;
+  s5 += s15 * 654183;
+  s6 -= s15 * 997805;
+  s7 += s15 * 136657;
+  s8 -= s15 * 683901;
+
+  s2 += s14 * 666643;
+  s3 += s14 * 470296;
+  s4 += s14 * 654183;
+  s5 -= s14 * 997805;
+  s6 += s14 * 136657;
+  s7 -= s14 * 683901;
+
+  s1 += s13 * 666643;
+  s2 += s13 * 470296;
+  s3 += s13 * 654183;
+  s4 -= s13 * 997805;
+  s5 += s13 * 136657;
+  s6 -= s13 * 683901;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  s[0] = s0 >> 0;
+  s[1] = s0 >> 8;
+  s[2] = (s0 >> 16) | (s1 << 5);
+  s[3] = s1 >> 3;
+  s[4] = s1 >> 11;
+  s[5] = (s1 >> 19) | (s2 << 2);
+  s[6] = s2 >> 6;
+  s[7] = (s2 >> 14) | (s3 << 7);
+  s[8] = s3 >> 1;
+  s[9] = s3 >> 9;
+  s[10] = (s3 >> 17) | (s4 << 4);
+  s[11] = s4 >> 4;
+  s[12] = s4 >> 12;
+  s[13] = (s4 >> 20) | (s5 << 1);
+  s[14] = s5 >> 7;
+  s[15] = (s5 >> 15) | (s6 << 6);
+  s[16] = s6 >> 2;
+  s[17] = s6 >> 10;
+  s[18] = (s6 >> 18) | (s7 << 3);
+  s[19] = s7 >> 5;
+  s[20] = s7 >> 13;
+  s[21] = s8 >> 0;
+  s[22] = s8 >> 8;
+  s[23] = (s8 >> 16) | (s9 << 5);
+  s[24] = s9 >> 3;
+  s[25] = s9 >> 11;
+  s[26] = (s9 >> 19) | (s10 << 2);
+  s[27] = s10 >> 6;
+  s[28] = (s10 >> 14) | (s11 << 7);
+  s[29] = s11 >> 1;
+  s[30] = s11 >> 9;
+  s[31] = s11 >> 17;
+}
+
+/* New code */
+
+static void fe_divpowm1(fe r, const fe u, const fe v) {
+  fe v3, uv7, t0, t1, t2;
+  int i;
+
+  fe_sq(v3, v);
+  fe_mul(v3, v3, v); /* v3 = v^3 */
+  fe_sq(uv7, v3);
+  fe_mul(uv7, uv7, v);
+  fe_mul(uv7, uv7, u); /* uv7 = uv^7 */
+
+  /*fe_pow22523(uv7, uv7);*/
+
+  /* From fe_pow22523.c */
+
+  fe_sq(t0, uv7);
+  fe_sq(t1, t0);
+  fe_sq(t1, t1);
+  fe_mul(t1, uv7, t1);
+  fe_mul(t0, t0, t1);
+  fe_sq(t0, t0);
+  fe_mul(t0, t1, t0);
+  fe_sq(t1, t0);
+  for (i = 0; i < 4; ++i) {
+    fe_sq(t1, t1);
+  }
+  fe_mul(t0, t1, t0);
+  fe_sq(t1, t0);
+  for (i = 0; i < 9; ++i) {
+    fe_sq(t1, t1);
+  }
+  fe_mul(t1, t1, t0);
+  fe_sq(t2, t1);
+  for (i = 0; i < 19; ++i) {
+    fe_sq(t2, t2);
+  }
+  fe_mul(t1, t2, t1);
+  for (i = 0; i < 10; ++i) {
+    fe_sq(t1, t1);
+  }
+  fe_mul(t0, t1, t0);
+  fe_sq(t1, t0);
+  for (i = 0; i < 49; ++i) {
+    fe_sq(t1, t1);
+  }
+  fe_mul(t1, t1, t0);
+  fe_sq(t2, t1);
+  for (i = 0; i < 99; ++i) {
+    fe_sq(t2, t2);
+  }
+  fe_mul(t1, t2, t1);
+  for (i = 0; i < 50; ++i) {
+    fe_sq(t1, t1);
+  }
+  fe_mul(t0, t1, t0);
+  fe_sq(t0, t0);
+  fe_sq(t0, t0);
+  fe_mul(t0, t0, uv7);
+
+  /* End fe_pow22523.c */
+  /* t0 = (uv^7)^((q-5)/8) */
+  fe_mul(t0, t0, v3);
+  fe_mul(r, t0, u); /* u^(m+1)v^(-(m+1)) */
+}
+
+static void ge_cached_0(ge_cached *r) {
+  fe_1(r->YplusX);
+  fe_1(r->YminusX);
+  fe_1(r->Z);
+  fe_0(r->T2d);
+}
+
+static void ge_cached_cmov(ge_cached *t, const ge_cached *u, unsigned char b) {
+  fe_cmov(t->YplusX, u->YplusX, b);
+  fe_cmov(t->YminusX, u->YminusX, b);
+  fe_cmov(t->Z, u->Z, b);
+  fe_cmov(t->T2d, u->T2d, b);
+}
+
+/* Assumes that a[31] <= 127 */
+void ge_scalarmult(ge_p2 *r, const unsigned char *a, const ge_p3 *A) {
+  signed char e[64];
+  int carry, carry2, i;
+  ge_cached Ai[8]; /* 1 * A, 2 * A, ..., 8 * A */
+  ge_p1p1 t;
+  ge_p3 u;
+
+  carry = 0; /* 0..1 */
+  for (i = 0; i < 31; i++) {
+    carry += a[i]; /* 0..256 */
+    carry2 = (carry + 8) >> 4; /* 0..16 */
+    e[2 * i] = carry - (carry2 << 4); /* -8..7 */
+    carry = (carry2 + 8) >> 4; /* 0..1 */
+    e[2 * i + 1] = carry2 - (carry << 4); /* -8..7 */
+  }
+  carry += a[31]; /* 0..128 */
+  carry2 = (carry + 8) >> 4; /* 0..8 */
+  e[62] = carry - (carry2 << 4); /* -8..7 */
+  e[63] = carry2; /* 0..8 */
+
+  ge_p3_to_cached(&Ai[0], A);
+  for (i = 0; i < 7; i++) {
+    ge_add(&t, A, &Ai[i]);
+    ge_p1p1_to_p3(&u, &t);
+    ge_p3_to_cached(&Ai[i + 1], &u);
+  }
+
+  ge_p2_0(r);
+  for (i = 63; i >= 0; i--) {
+    signed char b = e[i];
+    unsigned char bnegative = negative(b);
+    unsigned char babs = b - (((-bnegative) & b) << 1);
+    ge_cached cur, minuscur;
+    ge_p2_dbl(&t, r);
+    ge_p1p1_to_p2(r, &t);
+    ge_p2_dbl(&t, r);
+    ge_p1p1_to_p2(r, &t);
+    ge_p2_dbl(&t, r);
+    ge_p1p1_to_p2(r, &t);
+    ge_p2_dbl(&t, r);
+    ge_p1p1_to_p3(&u, &t);
+    ge_cached_0(&cur);
+    ge_cached_cmov(&cur, &Ai[0], equal(babs, 1));
+    ge_cached_cmov(&cur, &Ai[1], equal(babs, 2));
+    ge_cached_cmov(&cur, &Ai[2], equal(babs, 3));
+    ge_cached_cmov(&cur, &Ai[3], equal(babs, 4));
+    ge_cached_cmov(&cur, &Ai[4], equal(babs, 5));
+    ge_cached_cmov(&cur, &Ai[5], equal(babs, 6));
+    ge_cached_cmov(&cur, &Ai[6], equal(babs, 7));
+    ge_cached_cmov(&cur, &Ai[7], equal(babs, 8));
+    fe_copy(minuscur.YplusX, cur.YminusX);
+    fe_copy(minuscur.YminusX, cur.YplusX);
+    fe_copy(minuscur.Z, cur.Z);
+    fe_neg(minuscur.T2d, cur.T2d);
+    ge_cached_cmov(&cur, &minuscur, bnegative);
+    ge_add(&t, &u, &cur);
+    ge_p1p1_to_p2(r, &t);
+  }
+}
+
+void ge_double_scalarmult_precomp_vartime2(ge_p2 *r, const unsigned char *a, const ge_dsmp Ai, const unsigned char *b, const ge_dsmp Bi) {
+  signed char aslide[256];
+  signed char bslide[256];
+  ge_p1p1 t;
+  ge_p3 u;
+  int i;
+
+  slide(aslide, a);
+  slide(bslide, b);
+
+  ge_p2_0(r);
+
+  for (i = 255; i >= 0; --i) {
+    if (aslide[i] || bslide[i]) break;
+  }
+
+  for (; i >= 0; --i) {
+    ge_p2_dbl(&t, r);
+
+    if (aslide[i] > 0) {
+      ge_p1p1_to_p3(&u, &t);
+      ge_add(&t, &u, &Ai[aslide[i]/2]);
+    } else if (aslide[i] < 0) {
+      ge_p1p1_to_p3(&u, &t);
+      ge_sub(&t, &u, &Ai[(-aslide[i])/2]);
+    }
+
+    if (bslide[i] > 0) {
+      ge_p1p1_to_p3(&u, &t);
+      ge_add(&t, &u, &Bi[bslide[i]/2]);
+    } else if (bslide[i] < 0) {
+      ge_p1p1_to_p3(&u, &t);
+      ge_sub(&t, &u, &Bi[(-bslide[i])/2]);
+    }
+
+    ge_p1p1_to_p2(r, &t);
+  }
+}
+
+void ge_double_scalarmult_precomp_vartime(ge_p2 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b, const ge_dsmp Bi) {
+  ge_dsmp Ai; /* A, 3A, 5A, 7A, 9A, 11A, 13A, 15A */
+
+  ge_dsm_precomp(Ai, A);
+  ge_double_scalarmult_precomp_vartime2(r, a, Ai, b, Bi);
+}
+
+void ge_mul8(ge_p1p1 *r, const ge_p2 *t) {
+  ge_p2 u;
+  ge_p2_dbl(r, t);
+  ge_p1p1_to_p2(&u, r);
+  ge_p2_dbl(r, &u);
+  ge_p1p1_to_p2(&u, r);
+  ge_p2_dbl(r, &u);
+}
+
+void ge_fromfe_frombytes_vartime(ge_p2 *r, const unsigned char *s) {
+  fe u, v, w, x, y, z;
+  unsigned char sign;
+
+  /* From fe_frombytes.c */
+
+  int64_t h0 = load_4(s);
+  int64_t h1 = load_3(s + 4) << 6;
+  int64_t h2 = load_3(s + 7) << 5;
+  int64_t h3 = load_3(s + 10) << 3;
+  int64_t h4 = load_3(s + 13) << 2;
+  int64_t h5 = load_4(s + 16);
+  int64_t h6 = load_3(s + 20) << 7;
+  int64_t h7 = load_3(s + 23) << 5;
+  int64_t h8 = load_3(s + 26) << 4;
+  int64_t h9 = load_3(s + 29) << 2;
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+
+  carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+  carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+  carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+  carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+  carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+  carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+  carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+  carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+  carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+  carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+  u[0] = h0;
+  u[1] = h1;
+  u[2] = h2;
+  u[3] = h3;
+  u[4] = h4;
+  u[5] = h5;
+  u[6] = h6;
+  u[7] = h7;
+  u[8] = h8;
+  u[9] = h9;
+
+  /* End fe_frombytes.c */
+
+  fe_sq2(v, u); /* 2 * u^2 */
+  fe_1(w);
+  fe_add(w, v, w); /* w = 2 * u^2 + 1 */
+  fe_sq(x, w); /* w^2 */
+  fe_mul(y, fe_ma2, v); /* -2 * A^2 * u^2 */
+  fe_add(x, x, y); /* x = w^2 - 2 * A^2 * u^2 */
+  fe_divpowm1(r->X, w, x); /* (w / x)^(m + 1) */
+  fe_sq(y, r->X);
+  fe_mul(x, y, x);
+  fe_sub(y, w, x);
+  fe_copy(z, fe_ma);
+  if (fe_isnonzero(y)) {
+    fe_add(y, w, x);
+    if (fe_isnonzero(y)) {
+      goto negative;
+    } else {
+      fe_mul(r->X, r->X, fe_fffb1);
+    }
+  } else {
+    fe_mul(r->X, r->X, fe_fffb2);
+  }
+  fe_mul(r->X, r->X, u); /* u * sqrt(2 * A * (A + 2) * w / x) */
+  fe_mul(z, z, v); /* -2 * A * u^2 */
+  sign = 0;
+  goto setsign;
+negative:
+  fe_mul(x, x, fe_sqrtm1);
+  fe_sub(y, w, x);
+  if (fe_isnonzero(y)) {
+    assert((fe_add(y, w, x), !fe_isnonzero(y)));
+    fe_mul(r->X, r->X, fe_fffb3);
+  } else {
+    fe_mul(r->X, r->X, fe_fffb4);
+  }
+  /* r->X = sqrt(A * (A + 2) * w / x) */
+  /* z = -A */
+  sign = 1;
+setsign:
+  if (fe_isnegative(r->X) != sign) {
+    assert(fe_isnonzero(r->X));
+    fe_neg(r->X, r->X);
+  }
+  fe_add(r->Z, z, w);
+  fe_sub(r->Y, z, w);
+  fe_mul(r->X, r->X, r->Z);
+#if !defined(NDEBUG)
+  {
+    fe check_x, check_y, check_iz, check_v;
+    fe_invert(check_iz, r->Z);
+    fe_mul(check_x, r->X, check_iz);
+    fe_mul(check_y, r->Y, check_iz);
+    fe_sq(check_x, check_x);
+    fe_sq(check_y, check_y);
+    fe_mul(check_v, check_x, check_y);
+    fe_mul(check_v, fe_d, check_v);
+    fe_add(check_v, check_v, check_x);
+    fe_sub(check_v, check_v, check_y);
+    fe_1(check_x);
+    fe_add(check_v, check_v, check_x);
+    assert(!fe_isnonzero(check_v));
+  }
+#endif
+}
+
+void sc_0(unsigned char *s) {
+  int i;
+  for (i = 0; i < 32; i++) {
+    s[i] = 0;
+  }
+}
+
+void sc_reduce32(unsigned char *s) {
+  int64_t s0 = 2097151 & load_3(s);
+  int64_t s1 = 2097151 & (load_4(s + 2) >> 5);
+  int64_t s2 = 2097151 & (load_3(s + 5) >> 2);
+  int64_t s3 = 2097151 & (load_4(s + 7) >> 7);
+  int64_t s4 = 2097151 & (load_4(s + 10) >> 4);
+  int64_t s5 = 2097151 & (load_3(s + 13) >> 1);
+  int64_t s6 = 2097151 & (load_4(s + 15) >> 6);
+  int64_t s7 = 2097151 & (load_3(s + 18) >> 3);
+  int64_t s8 = 2097151 & load_3(s + 21);
+  int64_t s9 = 2097151 & (load_4(s + 23) >> 5);
+  int64_t s10 = 2097151 & (load_3(s + 26) >> 2);
+  int64_t s11 = (load_4(s + 28) >> 7);
+  int64_t s12 = 0;
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+  int64_t carry10;
+  int64_t carry11;
+
+  carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  s[0] = s0 >> 0;
+  s[1] = s0 >> 8;
+  s[2] = (s0 >> 16) | (s1 << 5);
+  s[3] = s1 >> 3;
+  s[4] = s1 >> 11;
+  s[5] = (s1 >> 19) | (s2 << 2);
+  s[6] = s2 >> 6;
+  s[7] = (s2 >> 14) | (s3 << 7);
+  s[8] = s3 >> 1;
+  s[9] = s3 >> 9;
+  s[10] = (s3 >> 17) | (s4 << 4);
+  s[11] = s4 >> 4;
+  s[12] = s4 >> 12;
+  s[13] = (s4 >> 20) | (s5 << 1);
+  s[14] = s5 >> 7;
+  s[15] = (s5 >> 15) | (s6 << 6);
+  s[16] = s6 >> 2;
+  s[17] = s6 >> 10;
+  s[18] = (s6 >> 18) | (s7 << 3);
+  s[19] = s7 >> 5;
+  s[20] = s7 >> 13;
+  s[21] = s8 >> 0;
+  s[22] = s8 >> 8;
+  s[23] = (s8 >> 16) | (s9 << 5);
+  s[24] = s9 >> 3;
+  s[25] = s9 >> 11;
+  s[26] = (s9 >> 19) | (s10 << 2);
+  s[27] = s10 >> 6;
+  s[28] = (s10 >> 14) | (s11 << 7);
+  s[29] = s11 >> 1;
+  s[30] = s11 >> 9;
+  s[31] = s11 >> 17;
+}
+
+void sc_add(unsigned char *s, const unsigned char *a, const unsigned char *b) {
+  int64_t a0 = 2097151 & load_3(a);
+  int64_t a1 = 2097151 & (load_4(a + 2) >> 5);
+  int64_t a2 = 2097151 & (load_3(a + 5) >> 2);
+  int64_t a3 = 2097151 & (load_4(a + 7) >> 7);
+  int64_t a4 = 2097151 & (load_4(a + 10) >> 4);
+  int64_t a5 = 2097151 & (load_3(a + 13) >> 1);
+  int64_t a6 = 2097151 & (load_4(a + 15) >> 6);
+  int64_t a7 = 2097151 & (load_3(a + 18) >> 3);
+  int64_t a8 = 2097151 & load_3(a + 21);
+  int64_t a9 = 2097151 & (load_4(a + 23) >> 5);
+  int64_t a10 = 2097151 & (load_3(a + 26) >> 2);
+  int64_t a11 = (load_4(a + 28) >> 7);
+  int64_t b0 = 2097151 & load_3(b);
+  int64_t b1 = 2097151 & (load_4(b + 2) >> 5);
+  int64_t b2 = 2097151 & (load_3(b + 5) >> 2);
+  int64_t b3 = 2097151 & (load_4(b + 7) >> 7);
+  int64_t b4 = 2097151 & (load_4(b + 10) >> 4);
+  int64_t b5 = 2097151 & (load_3(b + 13) >> 1);
+  int64_t b6 = 2097151 & (load_4(b + 15) >> 6);
+  int64_t b7 = 2097151 & (load_3(b + 18) >> 3);
+  int64_t b8 = 2097151 & load_3(b + 21);
+  int64_t b9 = 2097151 & (load_4(b + 23) >> 5);
+  int64_t b10 = 2097151 & (load_3(b + 26) >> 2);
+  int64_t b11 = (load_4(b + 28) >> 7);
+  int64_t s0 = a0 + b0;
+  int64_t s1 = a1 + b1;
+  int64_t s2 = a2 + b2;
+  int64_t s3 = a3 + b3;
+  int64_t s4 = a4 + b4;
+  int64_t s5 = a5 + b5;
+  int64_t s6 = a6 + b6;
+  int64_t s7 = a7 + b7;
+  int64_t s8 = a8 + b8;
+  int64_t s9 = a9 + b9;
+  int64_t s10 = a10 + b10;
+  int64_t s11 = a11 + b11;
+  int64_t s12 = 0;
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+  int64_t carry10;
+  int64_t carry11;
+
+  carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  s[0] = s0 >> 0;
+  s[1] = s0 >> 8;
+  s[2] = (s0 >> 16) | (s1 << 5);
+  s[3] = s1 >> 3;
+  s[4] = s1 >> 11;
+  s[5] = (s1 >> 19) | (s2 << 2);
+  s[6] = s2 >> 6;
+  s[7] = (s2 >> 14) | (s3 << 7);
+  s[8] = s3 >> 1;
+  s[9] = s3 >> 9;
+  s[10] = (s3 >> 17) | (s4 << 4);
+  s[11] = s4 >> 4;
+  s[12] = s4 >> 12;
+  s[13] = (s4 >> 20) | (s5 << 1);
+  s[14] = s5 >> 7;
+  s[15] = (s5 >> 15) | (s6 << 6);
+  s[16] = s6 >> 2;
+  s[17] = s6 >> 10;
+  s[18] = (s6 >> 18) | (s7 << 3);
+  s[19] = s7 >> 5;
+  s[20] = s7 >> 13;
+  s[21] = s8 >> 0;
+  s[22] = s8 >> 8;
+  s[23] = (s8 >> 16) | (s9 << 5);
+  s[24] = s9 >> 3;
+  s[25] = s9 >> 11;
+  s[26] = (s9 >> 19) | (s10 << 2);
+  s[27] = s10 >> 6;
+  s[28] = (s10 >> 14) | (s11 << 7);
+  s[29] = s11 >> 1;
+  s[30] = s11 >> 9;
+  s[31] = s11 >> 17;
+}
+
+void sc_sub(unsigned char *s, const unsigned char *a, const unsigned char *b) {
+  int64_t a0 = 2097151 & load_3(a);
+  int64_t a1 = 2097151 & (load_4(a + 2) >> 5);
+  int64_t a2 = 2097151 & (load_3(a + 5) >> 2);
+  int64_t a3 = 2097151 & (load_4(a + 7) >> 7);
+  int64_t a4 = 2097151 & (load_4(a + 10) >> 4);
+  int64_t a5 = 2097151 & (load_3(a + 13) >> 1);
+  int64_t a6 = 2097151 & (load_4(a + 15) >> 6);
+  int64_t a7 = 2097151 & (load_3(a + 18) >> 3);
+  int64_t a8 = 2097151 & load_3(a + 21);
+  int64_t a9 = 2097151 & (load_4(a + 23) >> 5);
+  int64_t a10 = 2097151 & (load_3(a + 26) >> 2);
+  int64_t a11 = (load_4(a + 28) >> 7);
+  int64_t b0 = 2097151 & load_3(b);
+  int64_t b1 = 2097151 & (load_4(b + 2) >> 5);
+  int64_t b2 = 2097151 & (load_3(b + 5) >> 2);
+  int64_t b3 = 2097151 & (load_4(b + 7) >> 7);
+  int64_t b4 = 2097151 & (load_4(b + 10) >> 4);
+  int64_t b5 = 2097151 & (load_3(b + 13) >> 1);
+  int64_t b6 = 2097151 & (load_4(b + 15) >> 6);
+  int64_t b7 = 2097151 & (load_3(b + 18) >> 3);
+  int64_t b8 = 2097151 & load_3(b + 21);
+  int64_t b9 = 2097151 & (load_4(b + 23) >> 5);
+  int64_t b10 = 2097151 & (load_3(b + 26) >> 2);
+  int64_t b11 = (load_4(b + 28) >> 7);
+  int64_t s0 = a0 - b0;
+  int64_t s1 = a1 - b1;
+  int64_t s2 = a2 - b2;
+  int64_t s3 = a3 - b3;
+  int64_t s4 = a4 - b4;
+  int64_t s5 = a5 - b5;
+  int64_t s6 = a6 - b6;
+  int64_t s7 = a7 - b7;
+  int64_t s8 = a8 - b8;
+  int64_t s9 = a9 - b9;
+  int64_t s10 = a10 - b10;
+  int64_t s11 = a11 - b11;
+  int64_t s12 = 0;
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+  int64_t carry10;
+  int64_t carry11;
+
+  carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  s[0] = s0 >> 0;
+  s[1] = s0 >> 8;
+  s[2] = (s0 >> 16) | (s1 << 5);
+  s[3] = s1 >> 3;
+  s[4] = s1 >> 11;
+  s[5] = (s1 >> 19) | (s2 << 2);
+  s[6] = s2 >> 6;
+  s[7] = (s2 >> 14) | (s3 << 7);
+  s[8] = s3 >> 1;
+  s[9] = s3 >> 9;
+  s[10] = (s3 >> 17) | (s4 << 4);
+  s[11] = s4 >> 4;
+  s[12] = s4 >> 12;
+  s[13] = (s4 >> 20) | (s5 << 1);
+  s[14] = s5 >> 7;
+  s[15] = (s5 >> 15) | (s6 << 6);
+  s[16] = s6 >> 2;
+  s[17] = s6 >> 10;
+  s[18] = (s6 >> 18) | (s7 << 3);
+  s[19] = s7 >> 5;
+  s[20] = s7 >> 13;
+  s[21] = s8 >> 0;
+  s[22] = s8 >> 8;
+  s[23] = (s8 >> 16) | (s9 << 5);
+  s[24] = s9 >> 3;
+  s[25] = s9 >> 11;
+  s[26] = (s9 >> 19) | (s10 << 2);
+  s[27] = s10 >> 6;
+  s[28] = (s10 >> 14) | (s11 << 7);
+  s[29] = s11 >> 1;
+  s[30] = s11 >> 9;
+  s[31] = s11 >> 17;
+}
+
+/*
+Input:
+  a[0]+256*a[1]+...+256^31*a[31] = a
+  b[0]+256*b[1]+...+256^31*b[31] = b
+  c[0]+256*c[1]+...+256^31*c[31] = c
+
+Output:
+  s[0]+256*s[1]+...+256^31*s[31] = (c-ab) mod l
+  where l = 2^252 + 27742317777372353535851937790883648493.
+*/
+
+void sc_mulsub(unsigned char *s, const unsigned char *a, const unsigned char *b, const unsigned char *c) {
+  int64_t a0 = 2097151 & load_3(a);
+  int64_t a1 = 2097151 & (load_4(a + 2) >> 5);
+  int64_t a2 = 2097151 & (load_3(a + 5) >> 2);
+  int64_t a3 = 2097151 & (load_4(a + 7) >> 7);
+  int64_t a4 = 2097151 & (load_4(a + 10) >> 4);
+  int64_t a5 = 2097151 & (load_3(a + 13) >> 1);
+  int64_t a6 = 2097151 & (load_4(a + 15) >> 6);
+  int64_t a7 = 2097151 & (load_3(a + 18) >> 3);
+  int64_t a8 = 2097151 & load_3(a + 21);
+  int64_t a9 = 2097151 & (load_4(a + 23) >> 5);
+  int64_t a10 = 2097151 & (load_3(a + 26) >> 2);
+  int64_t a11 = (load_4(a + 28) >> 7);
+  int64_t b0 = 2097151 & load_3(b);
+  int64_t b1 = 2097151 & (load_4(b + 2) >> 5);
+  int64_t b2 = 2097151 & (load_3(b + 5) >> 2);
+  int64_t b3 = 2097151 & (load_4(b + 7) >> 7);
+  int64_t b4 = 2097151 & (load_4(b + 10) >> 4);
+  int64_t b5 = 2097151 & (load_3(b + 13) >> 1);
+  int64_t b6 = 2097151 & (load_4(b + 15) >> 6);
+  int64_t b7 = 2097151 & (load_3(b + 18) >> 3);
+  int64_t b8 = 2097151 & load_3(b + 21);
+  int64_t b9 = 2097151 & (load_4(b + 23) >> 5);
+  int64_t b10 = 2097151 & (load_3(b + 26) >> 2);
+  int64_t b11 = (load_4(b + 28) >> 7);
+  int64_t c0 = 2097151 & load_3(c);
+  int64_t c1 = 2097151 & (load_4(c + 2) >> 5);
+  int64_t c2 = 2097151 & (load_3(c + 5) >> 2);
+  int64_t c3 = 2097151 & (load_4(c + 7) >> 7);
+  int64_t c4 = 2097151 & (load_4(c + 10) >> 4);
+  int64_t c5 = 2097151 & (load_3(c + 13) >> 1);
+  int64_t c6 = 2097151 & (load_4(c + 15) >> 6);
+  int64_t c7 = 2097151 & (load_3(c + 18) >> 3);
+  int64_t c8 = 2097151 & load_3(c + 21);
+  int64_t c9 = 2097151 & (load_4(c + 23) >> 5);
+  int64_t c10 = 2097151 & (load_3(c + 26) >> 2);
+  int64_t c11 = (load_4(c + 28) >> 7);
+  int64_t s0;
+  int64_t s1;
+  int64_t s2;
+  int64_t s3;
+  int64_t s4;
+  int64_t s5;
+  int64_t s6;
+  int64_t s7;
+  int64_t s8;
+  int64_t s9;
+  int64_t s10;
+  int64_t s11;
+  int64_t s12;
+  int64_t s13;
+  int64_t s14;
+  int64_t s15;
+  int64_t s16;
+  int64_t s17;
+  int64_t s18;
+  int64_t s19;
+  int64_t s20;
+  int64_t s21;
+  int64_t s22;
+  int64_t s23;
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+  int64_t carry10;
+  int64_t carry11;
+  int64_t carry12;
+  int64_t carry13;
+  int64_t carry14;
+  int64_t carry15;
+  int64_t carry16;
+  int64_t carry17;
+  int64_t carry18;
+  int64_t carry19;
+  int64_t carry20;
+  int64_t carry21;
+  int64_t carry22;
+
+  s0 = c0 - a0*b0;
+  s1 = c1 - (a0*b1 + a1*b0);
+  s2 = c2 - (a0*b2 + a1*b1 + a2*b0);
+  s3 = c3 - (a0*b3 + a1*b2 + a2*b1 + a3*b0);
+  s4 = c4 - (a0*b4 + a1*b3 + a2*b2 + a3*b1 + a4*b0);
+  s5 = c5 - (a0*b5 + a1*b4 + a2*b3 + a3*b2 + a4*b1 + a5*b0);
+  s6 = c6 - (a0*b6 + a1*b5 + a2*b4 + a3*b3 + a4*b2 + a5*b1 + a6*b0);
+  s7 = c7 - (a0*b7 + a1*b6 + a2*b5 + a3*b4 + a4*b3 + a5*b2 + a6*b1 + a7*b0);
+  s8 = c8 - (a0*b8 + a1*b7 + a2*b6 + a3*b5 + a4*b4 + a5*b3 + a6*b2 + a7*b1 + a8*b0);
+  s9 = c9 - (a0*b9 + a1*b8 + a2*b7 + a3*b6 + a4*b5 + a5*b4 + a6*b3 + a7*b2 + a8*b1 + a9*b0);
+  s10 = c10 - (a0*b10 + a1*b9 + a2*b8 + a3*b7 + a4*b6 + a5*b5 + a6*b4 + a7*b3 + a8*b2 + a9*b1 + a10*b0);
+  s11 = c11 - (a0*b11 + a1*b10 + a2*b9 + a3*b8 + a4*b7 + a5*b6 + a6*b5 + a7*b4 + a8*b3 + a9*b2 + a10*b1 + a11*b0);
+  s12 = -(a1*b11 + a2*b10 + a3*b9 + a4*b8 + a5*b7 + a6*b6 + a7*b5 + a8*b4 + a9*b3 + a10*b2 + a11*b1);
+  s13 = -(a2*b11 + a3*b10 + a4*b9 + a5*b8 + a6*b7 + a7*b6 + a8*b5 + a9*b4 + a10*b3 + a11*b2);
+  s14 = -(a3*b11 + a4*b10 + a5*b9 + a6*b8 + a7*b7 + a8*b6 + a9*b5 + a10*b4 + a11*b3);
+  s15 = -(a4*b11 + a5*b10 + a6*b9 + a7*b8 + a8*b7 + a9*b6 + a10*b5 + a11*b4);
+  s16 = -(a5*b11 + a6*b10 + a7*b9 + a8*b8 + a9*b7 + a10*b6 + a11*b5);
+  s17 = -(a6*b11 + a7*b10 + a8*b9 + a9*b8 + a10*b7 + a11*b6);
+  s18 = -(a7*b11 + a8*b10 + a9*b9 + a10*b8 + a11*b7);
+  s19 = -(a8*b11 + a9*b10 + a10*b9 + a11*b8);
+  s20 = -(a9*b11 + a10*b10 + a11*b9);
+  s21 = -(a10*b11 + a11*b10);
+  s22 = -a11*b11;
+  s23 = 0;
+
+  carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
+  carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
+  carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
+  carry18 = (s18 + (1<<20)) >> 21; s19 += carry18; s18 -= carry18 << 21;
+  carry20 = (s20 + (1<<20)) >> 21; s21 += carry20; s20 -= carry20 << 21;
+  carry22 = (s22 + (1<<20)) >> 21; s23 += carry22; s22 -= carry22 << 21;
+
+  carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+  carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
+  carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
+  carry17 = (s17 + (1<<20)) >> 21; s18 += carry17; s17 -= carry17 << 21;
+  carry19 = (s19 + (1<<20)) >> 21; s20 += carry19; s19 -= carry19 << 21;
+  carry21 = (s21 + (1<<20)) >> 21; s22 += carry21; s21 -= carry21 << 21;
+
+  s11 += s23 * 666643;
+  s12 += s23 * 470296;
+  s13 += s23 * 654183;
+  s14 -= s23 * 997805;
+  s15 += s23 * 136657;
+  s16 -= s23 * 683901;
+
+  s10 += s22 * 666643;
+  s11 += s22 * 470296;
+  s12 += s22 * 654183;
+  s13 -= s22 * 997805;
+  s14 += s22 * 136657;
+  s15 -= s22 * 683901;
+
+  s9 += s21 * 666643;
+  s10 += s21 * 470296;
+  s11 += s21 * 654183;
+  s12 -= s21 * 997805;
+  s13 += s21 * 136657;
+  s14 -= s21 * 683901;
+
+  s8 += s20 * 666643;
+  s9 += s20 * 470296;
+  s10 += s20 * 654183;
+  s11 -= s20 * 997805;
+  s12 += s20 * 136657;
+  s13 -= s20 * 683901;
+
+  s7 += s19 * 666643;
+  s8 += s19 * 470296;
+  s9 += s19 * 654183;
+  s10 -= s19 * 997805;
+  s11 += s19 * 136657;
+  s12 -= s19 * 683901;
+
+  s6 += s18 * 666643;
+  s7 += s18 * 470296;
+  s8 += s18 * 654183;
+  s9 -= s18 * 997805;
+  s10 += s18 * 136657;
+  s11 -= s18 * 683901;
+
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
+  carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
+  carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
+
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+  carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
+  carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
+
+  s5 += s17 * 666643;
+  s6 += s17 * 470296;
+  s7 += s17 * 654183;
+  s8 -= s17 * 997805;
+  s9 += s17 * 136657;
+  s10 -= s17 * 683901;
+
+  s4 += s16 * 666643;
+  s5 += s16 * 470296;
+  s6 += s16 * 654183;
+  s7 -= s16 * 997805;
+  s8 += s16 * 136657;
+  s9 -= s16 * 683901;
+
+  s3 += s15 * 666643;
+  s4 += s15 * 470296;
+  s5 += s15 * 654183;
+  s6 -= s15 * 997805;
+  s7 += s15 * 136657;
+  s8 -= s15 * 683901;
+
+  s2 += s14 * 666643;
+  s3 += s14 * 470296;
+  s4 += s14 * 654183;
+  s5 -= s14 * 997805;
+  s6 += s14 * 136657;
+  s7 -= s14 * 683901;
+
+  s1 += s13 * 666643;
+  s2 += s13 * 470296;
+  s3 += s13 * 654183;
+  s4 -= s13 * 997805;
+  s5 += s13 * 136657;
+  s6 -= s13 * 683901;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  s[0] = s0 >> 0;
+  s[1] = s0 >> 8;
+  s[2] = (s0 >> 16) | (s1 << 5);
+  s[3] = s1 >> 3;
+  s[4] = s1 >> 11;
+  s[5] = (s1 >> 19) | (s2 << 2);
+  s[6] = s2 >> 6;
+  s[7] = (s2 >> 14) | (s3 << 7);
+  s[8] = s3 >> 1;
+  s[9] = s3 >> 9;
+  s[10] = (s3 >> 17) | (s4 << 4);
+  s[11] = s4 >> 4;
+  s[12] = s4 >> 12;
+  s[13] = (s4 >> 20) | (s5 << 1);
+  s[14] = s5 >> 7;
+  s[15] = (s5 >> 15) | (s6 << 6);
+  s[16] = s6 >> 2;
+  s[17] = s6 >> 10;
+  s[18] = (s6 >> 18) | (s7 << 3);
+  s[19] = s7 >> 5;
+  s[20] = s7 >> 13;
+  s[21] = s8 >> 0;
+  s[22] = s8 >> 8;
+  s[23] = (s8 >> 16) | (s9 << 5);
+  s[24] = s9 >> 3;
+  s[25] = s9 >> 11;
+  s[26] = (s9 >> 19) | (s10 << 2);
+  s[27] = s10 >> 6;
+  s[28] = (s10 >> 14) | (s11 << 7);
+  s[29] = s11 >> 1;
+  s[30] = s11 >> 9;
+  s[31] = s11 >> 17;
+}
+
+//copied from above and modified
+/*
+Input:
+  a[0]+256*a[1]+...+256^31*a[31] = a
+  b[0]+256*b[1]+...+256^31*b[31] = b
+
+Output:
+  s[0]+256*s[1]+...+256^31*s[31] = (ab) mod l
+  where l = 2^252 + 27742317777372353535851937790883648493.
+*/
+void sc_mul(unsigned char *s, const unsigned char *a, const unsigned char *b) {
+  int64_t a0 = 2097151 & load_3(a);
+  int64_t a1 = 2097151 & (load_4(a + 2) >> 5);
+  int64_t a2 = 2097151 & (load_3(a + 5) >> 2);
+  int64_t a3 = 2097151 & (load_4(a + 7) >> 7);
+  int64_t a4 = 2097151 & (load_4(a + 10) >> 4);
+  int64_t a5 = 2097151 & (load_3(a + 13) >> 1);
+  int64_t a6 = 2097151 & (load_4(a + 15) >> 6);
+  int64_t a7 = 2097151 & (load_3(a + 18) >> 3);
+  int64_t a8 = 2097151 & load_3(a + 21);
+  int64_t a9 = 2097151 & (load_4(a + 23) >> 5);
+  int64_t a10 = 2097151 & (load_3(a + 26) >> 2);
+  int64_t a11 = (load_4(a + 28) >> 7);
+  int64_t b0 = 2097151 & load_3(b);
+  int64_t b1 = 2097151 & (load_4(b + 2) >> 5);
+  int64_t b2 = 2097151 & (load_3(b + 5) >> 2);
+  int64_t b3 = 2097151 & (load_4(b + 7) >> 7);
+  int64_t b4 = 2097151 & (load_4(b + 10) >> 4);
+  int64_t b5 = 2097151 & (load_3(b + 13) >> 1);
+  int64_t b6 = 2097151 & (load_4(b + 15) >> 6);
+  int64_t b7 = 2097151 & (load_3(b + 18) >> 3);
+  int64_t b8 = 2097151 & load_3(b + 21);
+  int64_t b9 = 2097151 & (load_4(b + 23) >> 5);
+  int64_t b10 = 2097151 & (load_3(b + 26) >> 2);
+  int64_t b11 = (load_4(b + 28) >> 7);
+  int64_t s0;
+  int64_t s1;
+  int64_t s2;
+  int64_t s3;
+  int64_t s4;
+  int64_t s5;
+  int64_t s6;
+  int64_t s7;
+  int64_t s8;
+  int64_t s9;
+  int64_t s10;
+  int64_t s11;
+  int64_t s12;
+  int64_t s13;
+  int64_t s14;
+  int64_t s15;
+  int64_t s16;
+  int64_t s17;
+  int64_t s18;
+  int64_t s19;
+  int64_t s20;
+  int64_t s21;
+  int64_t s22;
+  int64_t s23;
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+  int64_t carry10;
+  int64_t carry11;
+  int64_t carry12;
+  int64_t carry13;
+  int64_t carry14;
+  int64_t carry15;
+  int64_t carry16;
+  int64_t carry17;
+  int64_t carry18;
+  int64_t carry19;
+  int64_t carry20;
+  int64_t carry21;
+  int64_t carry22;
+
+  s0 = a0*b0;
+  s1 = (a0*b1 + a1*b0);
+  s2 = (a0*b2 + a1*b1 + a2*b0);
+  s3 = (a0*b3 + a1*b2 + a2*b1 + a3*b0);
+  s4 = (a0*b4 + a1*b3 + a2*b2 + a3*b1 + a4*b0);
+  s5 = (a0*b5 + a1*b4 + a2*b3 + a3*b2 + a4*b1 + a5*b0);
+  s6 = (a0*b6 + a1*b5 + a2*b4 + a3*b3 + a4*b2 + a5*b1 + a6*b0);
+  s7 = (a0*b7 + a1*b6 + a2*b5 + a3*b4 + a4*b3 + a5*b2 + a6*b1 + a7*b0);
+  s8 = (a0*b8 + a1*b7 + a2*b6 + a3*b5 + a4*b4 + a5*b3 + a6*b2 + a7*b1 + a8*b0);
+  s9 = (a0*b9 + a1*b8 + a2*b7 + a3*b6 + a4*b5 + a5*b4 + a6*b3 + a7*b2 + a8*b1 + a9*b0);
+  s10 = (a0*b10 + a1*b9 + a2*b8 + a3*b7 + a4*b6 + a5*b5 + a6*b4 + a7*b3 + a8*b2 + a9*b1 + a10*b0);
+  s11 = (a0*b11 + a1*b10 + a2*b9 + a3*b8 + a4*b7 + a5*b6 + a6*b5 + a7*b4 + a8*b3 + a9*b2 + a10*b1 + a11*b0);
+  s12 = (a1*b11 + a2*b10 + a3*b9 + a4*b8 + a5*b7 + a6*b6 + a7*b5 + a8*b4 + a9*b3 + a10*b2 + a11*b1);
+  s13 = (a2*b11 + a3*b10 + a4*b9 + a5*b8 + a6*b7 + a7*b6 + a8*b5 + a9*b4 + a10*b3 + a11*b2);
+  s14 = (a3*b11 + a4*b10 + a5*b9 + a6*b8 + a7*b7 + a8*b6 + a9*b5 + a10*b4 + a11*b3);
+  s15 = (a4*b11 + a5*b10 + a6*b9 + a7*b8 + a8*b7 + a9*b6 + a10*b5 + a11*b4);
+  s16 = (a5*b11 + a6*b10 + a7*b9 + a8*b8 + a9*b7 + a10*b6 + a11*b5);
+  s17 = (a6*b11 + a7*b10 + a8*b9 + a9*b8 + a10*b7 + a11*b6);
+  s18 = (a7*b11 + a8*b10 + a9*b9 + a10*b8 + a11*b7);
+  s19 = (a8*b11 + a9*b10 + a10*b9 + a11*b8);
+  s20 = (a9*b11 + a10*b10 + a11*b9);
+  s21 = (a10*b11 + a11*b10);
+  s22 = a11*b11;
+  s23 = 0;
+
+  carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
+  carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
+  carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
+  carry18 = (s18 + (1<<20)) >> 21; s19 += carry18; s18 -= carry18 << 21;
+  carry20 = (s20 + (1<<20)) >> 21; s21 += carry20; s20 -= carry20 << 21;
+  carry22 = (s22 + (1<<20)) >> 21; s23 += carry22; s22 -= carry22 << 21;
+
+  carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+  carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
+  carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
+  carry17 = (s17 + (1<<20)) >> 21; s18 += carry17; s17 -= carry17 << 21;
+  carry19 = (s19 + (1<<20)) >> 21; s20 += carry19; s19 -= carry19 << 21;
+  carry21 = (s21 + (1<<20)) >> 21; s22 += carry21; s21 -= carry21 << 21;
+
+  s11 += s23 * 666643;
+  s12 += s23 * 470296;
+  s13 += s23 * 654183;
+  s14 -= s23 * 997805;
+  s15 += s23 * 136657;
+  s16 -= s23 * 683901;
+
+  s10 += s22 * 666643;
+  s11 += s22 * 470296;
+  s12 += s22 * 654183;
+  s13 -= s22 * 997805;
+  s14 += s22 * 136657;
+  s15 -= s22 * 683901;
+
+  s9 += s21 * 666643;
+  s10 += s21 * 470296;
+  s11 += s21 * 654183;
+  s12 -= s21 * 997805;
+  s13 += s21 * 136657;
+  s14 -= s21 * 683901;
+
+  s8 += s20 * 666643;
+  s9 += s20 * 470296;
+  s10 += s20 * 654183;
+  s11 -= s20 * 997805;
+  s12 += s20 * 136657;
+  s13 -= s20 * 683901;
+
+  s7 += s19 * 666643;
+  s8 += s19 * 470296;
+  s9 += s19 * 654183;
+  s10 -= s19 * 997805;
+  s11 += s19 * 136657;
+  s12 -= s19 * 683901;
+
+  s6 += s18 * 666643;
+  s7 += s18 * 470296;
+  s8 += s18 * 654183;
+  s9 -= s18 * 997805;
+  s10 += s18 * 136657;
+  s11 -= s18 * 683901;
+
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
+  carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
+  carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
+
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+  carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
+  carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
+
+  s5 += s17 * 666643;
+  s6 += s17 * 470296;
+  s7 += s17 * 654183;
+  s8 -= s17 * 997805;
+  s9 += s17 * 136657;
+  s10 -= s17 * 683901;
+
+  s4 += s16 * 666643;
+  s5 += s16 * 470296;
+  s6 += s16 * 654183;
+  s7 -= s16 * 997805;
+  s8 += s16 * 136657;
+  s9 -= s16 * 683901;
+
+  s3 += s15 * 666643;
+  s4 += s15 * 470296;
+  s5 += s15 * 654183;
+  s6 -= s15 * 997805;
+  s7 += s15 * 136657;
+  s8 -= s15 * 683901;
+
+  s2 += s14 * 666643;
+  s3 += s14 * 470296;
+  s4 += s14 * 654183;
+  s5 -= s14 * 997805;
+  s6 += s14 * 136657;
+  s7 -= s14 * 683901;
+
+  s1 += s13 * 666643;
+  s2 += s13 * 470296;
+  s3 += s13 * 654183;
+  s4 -= s13 * 997805;
+  s5 += s13 * 136657;
+  s6 -= s13 * 683901;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  s[0] = s0 >> 0;
+  s[1] = s0 >> 8;
+  s[2] = (s0 >> 16) | (s1 << 5);
+  s[3] = s1 >> 3;
+  s[4] = s1 >> 11;
+  s[5] = (s1 >> 19) | (s2 << 2);
+  s[6] = s2 >> 6;
+  s[7] = (s2 >> 14) | (s3 << 7);
+  s[8] = s3 >> 1;
+  s[9] = s3 >> 9;
+  s[10] = (s3 >> 17) | (s4 << 4);
+  s[11] = s4 >> 4;
+  s[12] = s4 >> 12;
+  s[13] = (s4 >> 20) | (s5 << 1);
+  s[14] = s5 >> 7;
+  s[15] = (s5 >> 15) | (s6 << 6);
+  s[16] = s6 >> 2;
+  s[17] = s6 >> 10;
+  s[18] = (s6 >> 18) | (s7 << 3);
+  s[19] = s7 >> 5;
+  s[20] = s7 >> 13;
+  s[21] = s8 >> 0;
+  s[22] = s8 >> 8;
+  s[23] = (s8 >> 16) | (s9 << 5);
+  s[24] = s9 >> 3;
+  s[25] = s9 >> 11;
+  s[26] = (s9 >> 19) | (s10 << 2);
+  s[27] = s10 >> 6;
+  s[28] = (s10 >> 14) | (s11 << 7);
+  s[29] = s11 >> 1;
+  s[30] = s11 >> 9;
+  s[31] = s11 >> 17;
+}
+
+//copied from above and modified
+/*
+Input:
+  a[0]+256*a[1]+...+256^31*a[31] = a
+  b[0]+256*b[1]+...+256^31*b[31] = b
+  c[0]+256*c[1]+...+256^31*c[31] = c
+
+Output:
+  s[0]+256*s[1]+...+256^31*s[31] = (c+ab) mod l
+  where l = 2^252 + 27742317777372353535851937790883648493.
+*/
+
+void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b, const unsigned char *c) {
+  int64_t a0 = 2097151 & load_3(a);
+  int64_t a1 = 2097151 & (load_4(a + 2) >> 5);
+  int64_t a2 = 2097151 & (load_3(a + 5) >> 2);
+  int64_t a3 = 2097151 & (load_4(a + 7) >> 7);
+  int64_t a4 = 2097151 & (load_4(a + 10) >> 4);
+  int64_t a5 = 2097151 & (load_3(a + 13) >> 1);
+  int64_t a6 = 2097151 & (load_4(a + 15) >> 6);
+  int64_t a7 = 2097151 & (load_3(a + 18) >> 3);
+  int64_t a8 = 2097151 & load_3(a + 21);
+  int64_t a9 = 2097151 & (load_4(a + 23) >> 5);
+  int64_t a10 = 2097151 & (load_3(a + 26) >> 2);
+  int64_t a11 = (load_4(a + 28) >> 7);
+  int64_t b0 = 2097151 & load_3(b);
+  int64_t b1 = 2097151 & (load_4(b + 2) >> 5);
+  int64_t b2 = 2097151 & (load_3(b + 5) >> 2);
+  int64_t b3 = 2097151 & (load_4(b + 7) >> 7);
+  int64_t b4 = 2097151 & (load_4(b + 10) >> 4);
+  int64_t b5 = 2097151 & (load_3(b + 13) >> 1);
+  int64_t b6 = 2097151 & (load_4(b + 15) >> 6);
+  int64_t b7 = 2097151 & (load_3(b + 18) >> 3);
+  int64_t b8 = 2097151 & load_3(b + 21);
+  int64_t b9 = 2097151 & (load_4(b + 23) >> 5);
+  int64_t b10 = 2097151 & (load_3(b + 26) >> 2);
+  int64_t b11 = (load_4(b + 28) >> 7);
+  int64_t c0 = 2097151 & load_3(c);
+  int64_t c1 = 2097151 & (load_4(c + 2) >> 5);
+  int64_t c2 = 2097151 & (load_3(c + 5) >> 2);
+  int64_t c3 = 2097151 & (load_4(c + 7) >> 7);
+  int64_t c4 = 2097151 & (load_4(c + 10) >> 4);
+  int64_t c5 = 2097151 & (load_3(c + 13) >> 1);
+  int64_t c6 = 2097151 & (load_4(c + 15) >> 6);
+  int64_t c7 = 2097151 & (load_3(c + 18) >> 3);
+  int64_t c8 = 2097151 & load_3(c + 21);
+  int64_t c9 = 2097151 & (load_4(c + 23) >> 5);
+  int64_t c10 = 2097151 & (load_3(c + 26) >> 2);
+  int64_t c11 = (load_4(c + 28) >> 7);
+  int64_t s0;
+  int64_t s1;
+  int64_t s2;
+  int64_t s3;
+  int64_t s4;
+  int64_t s5;
+  int64_t s6;
+  int64_t s7;
+  int64_t s8;
+  int64_t s9;
+  int64_t s10;
+  int64_t s11;
+  int64_t s12;
+  int64_t s13;
+  int64_t s14;
+  int64_t s15;
+  int64_t s16;
+  int64_t s17;
+  int64_t s18;
+  int64_t s19;
+  int64_t s20;
+  int64_t s21;
+  int64_t s22;
+  int64_t s23;
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+  int64_t carry10;
+  int64_t carry11;
+  int64_t carry12;
+  int64_t carry13;
+  int64_t carry14;
+  int64_t carry15;
+  int64_t carry16;
+  int64_t carry17;
+  int64_t carry18;
+  int64_t carry19;
+  int64_t carry20;
+  int64_t carry21;
+  int64_t carry22;
+
+  s0 = c0 + a0*b0;
+  s1 = c1 + (a0*b1 + a1*b0);
+  s2 = c2 + (a0*b2 + a1*b1 + a2*b0);
+  s3 = c3 + (a0*b3 + a1*b2 + a2*b1 + a3*b0);
+  s4 = c4 + (a0*b4 + a1*b3 + a2*b2 + a3*b1 + a4*b0);
+  s5 = c5 + (a0*b5 + a1*b4 + a2*b3 + a3*b2 + a4*b1 + a5*b0);
+  s6 = c6 + (a0*b6 + a1*b5 + a2*b4 + a3*b3 + a4*b2 + a5*b1 + a6*b0);
+  s7 = c7 + (a0*b7 + a1*b6 + a2*b5 + a3*b4 + a4*b3 + a5*b2 + a6*b1 + a7*b0);
+  s8 = c8 + (a0*b8 + a1*b7 + a2*b6 + a3*b5 + a4*b4 + a5*b3 + a6*b2 + a7*b1 + a8*b0);
+  s9 = c9 + (a0*b9 + a1*b8 + a2*b7 + a3*b6 + a4*b5 + a5*b4 + a6*b3 + a7*b2 + a8*b1 + a9*b0);
+  s10 = c10 + (a0*b10 + a1*b9 + a2*b8 + a3*b7 + a4*b6 + a5*b5 + a6*b4 + a7*b3 + a8*b2 + a9*b1 + a10*b0);
+  s11 = c11 + (a0*b11 + a1*b10 + a2*b9 + a3*b8 + a4*b7 + a5*b6 + a6*b5 + a7*b4 + a8*b3 + a9*b2 + a10*b1 + a11*b0);
+  s12 = (a1*b11 + a2*b10 + a3*b9 + a4*b8 + a5*b7 + a6*b6 + a7*b5 + a8*b4 + a9*b3 + a10*b2 + a11*b1);
+  s13 = (a2*b11 + a3*b10 + a4*b9 + a5*b8 + a6*b7 + a7*b6 + a8*b5 + a9*b4 + a10*b3 + a11*b2);
+  s14 = (a3*b11 + a4*b10 + a5*b9 + a6*b8 + a7*b7 + a8*b6 + a9*b5 + a10*b4 + a11*b3);
+  s15 = (a4*b11 + a5*b10 + a6*b9 + a7*b8 + a8*b7 + a9*b6 + a10*b5 + a11*b4);
+  s16 = (a5*b11 + a6*b10 + a7*b9 + a8*b8 + a9*b7 + a10*b6 + a11*b5);
+  s17 = (a6*b11 + a7*b10 + a8*b9 + a9*b8 + a10*b7 + a11*b6);
+  s18 = (a7*b11 + a8*b10 + a9*b9 + a10*b8 + a11*b7);
+  s19 = (a8*b11 + a9*b10 + a10*b9 + a11*b8);
+  s20 = (a9*b11 + a10*b10 + a11*b9);
+  s21 = (a10*b11 + a11*b10);
+  s22 = a11*b11;
+  s23 = 0;
+
+  carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
+  carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
+  carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
+  carry18 = (s18 + (1<<20)) >> 21; s19 += carry18; s18 -= carry18 << 21;
+  carry20 = (s20 + (1<<20)) >> 21; s21 += carry20; s20 -= carry20 << 21;
+  carry22 = (s22 + (1<<20)) >> 21; s23 += carry22; s22 -= carry22 << 21;
+
+  carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+  carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
+  carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
+  carry17 = (s17 + (1<<20)) >> 21; s18 += carry17; s17 -= carry17 << 21;
+  carry19 = (s19 + (1<<20)) >> 21; s20 += carry19; s19 -= carry19 << 21;
+  carry21 = (s21 + (1<<20)) >> 21; s22 += carry21; s21 -= carry21 << 21;
+
+  s11 += s23 * 666643;
+  s12 += s23 * 470296;
+  s13 += s23 * 654183;
+  s14 -= s23 * 997805;
+  s15 += s23 * 136657;
+  s16 -= s23 * 683901;
+
+  s10 += s22 * 666643;
+  s11 += s22 * 470296;
+  s12 += s22 * 654183;
+  s13 -= s22 * 997805;
+  s14 += s22 * 136657;
+  s15 -= s22 * 683901;
+
+  s9 += s21 * 666643;
+  s10 += s21 * 470296;
+  s11 += s21 * 654183;
+  s12 -= s21 * 997805;
+  s13 += s21 * 136657;
+  s14 -= s21 * 683901;
+
+  s8 += s20 * 666643;
+  s9 += s20 * 470296;
+  s10 += s20 * 654183;
+  s11 -= s20 * 997805;
+  s12 += s20 * 136657;
+  s13 -= s20 * 683901;
+
+  s7 += s19 * 666643;
+  s8 += s19 * 470296;
+  s9 += s19 * 654183;
+  s10 -= s19 * 997805;
+  s11 += s19 * 136657;
+  s12 -= s19 * 683901;
+
+  s6 += s18 * 666643;
+  s7 += s18 * 470296;
+  s8 += s18 * 654183;
+  s9 -= s18 * 997805;
+  s10 += s18 * 136657;
+  s11 -= s18 * 683901;
+
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
+  carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
+  carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
+
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+  carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
+  carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
+
+  s5 += s17 * 666643;
+  s6 += s17 * 470296;
+  s7 += s17 * 654183;
+  s8 -= s17 * 997805;
+  s9 += s17 * 136657;
+  s10 -= s17 * 683901;
+
+  s4 += s16 * 666643;
+  s5 += s16 * 470296;
+  s6 += s16 * 654183;
+  s7 -= s16 * 997805;
+  s8 += s16 * 136657;
+  s9 -= s16 * 683901;
+
+  s3 += s15 * 666643;
+  s4 += s15 * 470296;
+  s5 += s15 * 654183;
+  s6 -= s15 * 997805;
+  s7 += s15 * 136657;
+  s8 -= s15 * 683901;
+
+  s2 += s14 * 666643;
+  s3 += s14 * 470296;
+  s4 += s14 * 654183;
+  s5 -= s14 * 997805;
+  s6 += s14 * 136657;
+  s7 -= s14 * 683901;
+
+  s1 += s13 * 666643;
+  s2 += s13 * 470296;
+  s3 += s13 * 654183;
+  s4 -= s13 * 997805;
+  s5 += s13 * 136657;
+  s6 -= s13 * 683901;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  s[0] = s0 >> 0;
+  s[1] = s0 >> 8;
+  s[2] = (s0 >> 16) | (s1 << 5);
+  s[3] = s1 >> 3;
+  s[4] = s1 >> 11;
+  s[5] = (s1 >> 19) | (s2 << 2);
+  s[6] = s2 >> 6;
+  s[7] = (s2 >> 14) | (s3 << 7);
+  s[8] = s3 >> 1;
+  s[9] = s3 >> 9;
+  s[10] = (s3 >> 17) | (s4 << 4);
+  s[11] = s4 >> 4;
+  s[12] = s4 >> 12;
+  s[13] = (s4 >> 20) | (s5 << 1);
+  s[14] = s5 >> 7;
+  s[15] = (s5 >> 15) | (s6 << 6);
+  s[16] = s6 >> 2;
+  s[17] = s6 >> 10;
+  s[18] = (s6 >> 18) | (s7 << 3);
+  s[19] = s7 >> 5;
+  s[20] = s7 >> 13;
+  s[21] = s8 >> 0;
+  s[22] = s8 >> 8;
+  s[23] = (s8 >> 16) | (s9 << 5);
+  s[24] = s9 >> 3;
+  s[25] = s9 >> 11;
+  s[26] = (s9 >> 19) | (s10 << 2);
+  s[27] = s10 >> 6;
+  s[28] = (s10 >> 14) | (s11 << 7);
+  s[29] = s11 >> 1;
+  s[30] = s11 >> 9;
+  s[31] = s11 >> 17;
+}
+
+/* Assumes that a != INT64_MIN */
+static int64_t signum(int64_t a) {
+  return (a >> 63) - ((-a) >> 63);
+}
+
+int sc_check(const unsigned char *s) {
+  int64_t s0 = load_4(s);
+  int64_t s1 = load_4(s + 4);
+  int64_t s2 = load_4(s + 8);
+  int64_t s3 = load_4(s + 12);
+  int64_t s4 = load_4(s + 16);
+  int64_t s5 = load_4(s + 20);
+  int64_t s6 = load_4(s + 24);
+  int64_t s7 = load_4(s + 28);
+  return (signum(1559614444 - s0) + (signum(1477600026 - s1) << 1) + (signum(2734136534 - s2) << 2) + (signum(350157278 - s3) << 3) + (signum(-s4) << 4) + (signum(-s5) << 5) + (signum(-s6) << 6) + (signum(268435456 - s7) << 7)) >> 8;
+}
+
+int sc_isnonzero(const unsigned char *s) {
+  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;
+}
diff --git a/crypt/monero_crypto/crypto-ops.h b/crypt/monero_crypto/crypto-ops.h
new file mode 100644
index 0000000000..c764555517
--- /dev/null
+++ b/crypt/monero_crypto/crypto-ops.h
@@ -0,0 +1,156 @@
+// 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
+
+#pragma once
+
+/* From fe.h */
+
+typedef int32_t fe[10];
+
+/* From ge.h */
+
+typedef struct {
+  fe X;
+  fe Y;
+  fe Z;
+} ge_p2;
+
+typedef struct {
+  fe X;
+  fe Y;
+  fe Z;
+  fe T;
+} ge_p3;
+
+typedef struct {
+  fe X;
+  fe Y;
+  fe Z;
+  fe T;
+} ge_p1p1;
+
+typedef struct {
+  fe yplusx;
+  fe yminusx;
+  fe xy2d;
+} ge_precomp;
+
+typedef struct {
+  fe YplusX;
+  fe YminusX;
+  fe Z;
+  fe T2d;
+} ge_cached;
+
+/* From ge_add.c */
+
+void ge_add(ge_p1p1 *, const ge_p3 *, const ge_cached *);
+
+/* From ge_double_scalarmult.c, modified */
+
+typedef ge_cached ge_dsmp[8];
+extern const ge_precomp ge_Bi[8];
+void ge_dsm_precomp(ge_dsmp r, const ge_p3 *s);
+void ge_double_scalarmult_base_vartime(ge_p2 *, const unsigned char *, const ge_p3 *, const unsigned char *);
+
+/* From ge_frombytes.c, modified */
+
+extern const fe fe_sqrtm1;
+extern const fe fe_d;
+int ge_frombytes_vartime(ge_p3 *, const unsigned char *);
+
+/* From ge_p1p1_to_p2.c */
+
+void ge_p1p1_to_p2(ge_p2 *, const ge_p1p1 *);
+
+/* From ge_p1p1_to_p3.c */
+
+void ge_p1p1_to_p3(ge_p3 *, const ge_p1p1 *);
+
+/* From ge_p2_dbl.c */
+
+void ge_p2_dbl(ge_p1p1 *, const ge_p2 *);
+
+/* From ge_p3_to_cached.c */
+
+extern const fe fe_d2;
+void ge_p3_to_cached(ge_cached *, const ge_p3 *);
+
+/* From ge_p3_to_p2.c */
+
+void ge_p3_to_p2(ge_p2 *, const ge_p3 *);
+
+/* From ge_p3_tobytes.c */
+
+void ge_p3_tobytes(unsigned char *, const ge_p3 *);
+
+/* From ge_scalarmult_base.c */
+
+extern const ge_precomp ge_base[32][8];
+void ge_scalarmult_base(ge_p3 *, const unsigned char *);
+
+/* From ge_tobytes.c */
+
+void ge_tobytes(unsigned char *, const ge_p2 *);
+
+/* From sc_reduce.c */
+
+void sc_reduce(unsigned char *);
+
+/* New code */
+
+void ge_scalarmult(ge_p2 *, const unsigned char *, const ge_p3 *);
+void ge_double_scalarmult_precomp_vartime(ge_p2 *, const unsigned char *, const ge_p3 *, const unsigned char *, const ge_dsmp);
+void ge_double_scalarmult_precomp_vartime2(ge_p2 *, const unsigned char *, const ge_dsmp, const unsigned char *, const ge_dsmp);
+void ge_mul8(ge_p1p1 *, const ge_p2 *);
+extern const fe fe_ma2;
+extern const fe fe_ma;
+extern const fe fe_fffb1;
+extern const fe fe_fffb2;
+extern const fe fe_fffb3;
+extern const fe fe_fffb4;
+void ge_fromfe_frombytes_vartime(ge_p2 *, const unsigned char *);
+void sc_0(unsigned char *);
+void sc_reduce32(unsigned char *);
+void sc_add(unsigned char *, const unsigned char *, const unsigned char *);
+void sc_sub(unsigned char *, const unsigned char *, const unsigned char *);
+void sc_mulsub(unsigned char *, const unsigned char *, const unsigned char *, const unsigned char *);
+void sc_mul(unsigned char *, const unsigned char *, const unsigned char *);
+void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b, const unsigned char *c);
+int sc_check(const unsigned char *);
+int sc_isnonzero(const unsigned char *); /* Doesn't normalize */
+
+// internal
+uint64_t load_3(const unsigned char *in);
+uint64_t load_4(const unsigned char *in);
+void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q);
+void fe_add(fe h, const fe f, const fe g);
+void fe_tobytes(unsigned char *, const fe);
+void fe_invert(fe out, const fe z);
diff --git a/crypt/monero_crypto/crypto.cpp b/crypt/monero_crypto/crypto.cpp
new file mode 100644
index 0000000000..95ba34828d
--- /dev/null
+++ b/crypt/monero_crypto/crypto.cpp
@@ -0,0 +1,564 @@
+// 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
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <memory>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/lock_guard.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include "common/varint.h"
+#include "warnings.h"
+#include "crypto.h"
+#include "hash.h"
+
+namespace crypto {
+
+  using std::abort;
+  using std::int32_t;
+  using std::int64_t;
+  using std::size_t;
+  using std::uint32_t;
+  using std::uint64_t;
+
+  extern "C" {
+#include "crypto-ops.h"
+#include "random.h"
+  }
+
+  boost::mutex random_lock;
+
+  static inline unsigned char *operator &(ec_point &point) {
+    return &reinterpret_cast<unsigned char &>(point);
+  }
+
+  static inline const unsigned char *operator &(const ec_point &point) {
+    return &reinterpret_cast<const unsigned char &>(point);
+  }
+
+  static inline unsigned char *operator &(ec_scalar &scalar) {
+    return &reinterpret_cast<unsigned char &>(scalar);
+  }
+
+  static inline const unsigned char *operator &(const ec_scalar &scalar) {
+    return &reinterpret_cast<const unsigned char &>(scalar);
+  }
+
+  /* generate a random 32-byte (256-bit) integer and copy it to res */
+  static inline void random_scalar_not_thread_safe(ec_scalar &res) {
+    unsigned char tmp[64];
+    generate_random_bytes_not_thread_safe(64, tmp);
+    sc_reduce(tmp);
+    memcpy(&res, tmp, 32);
+  }
+  static inline void random_scalar(ec_scalar &res) {
+    boost::lock_guard<boost::mutex> lock(random_lock);
+    random_scalar_not_thread_safe(res);
+  }
+
+  void hash_to_scalar(const void *data, size_t length, ec_scalar &res) {
+    cn_fast_hash(data, length, reinterpret_cast<hash &>(res));
+    sc_reduce32(&res);
+  }
+
+  /* 
+   * generate public and secret keys from a random 256-bit integer
+   * TODO: allow specifiying random value (for wallet recovery)
+   * 
+   */
+  secret_key crypto_ops::generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key, bool recover) {
+    ge_p3 point;
+
+    secret_key rng;
+
+    if (recover)
+    {
+      rng = recovery_key;
+    }
+    else
+    {
+      random_scalar(rng);
+    }
+    sec = rng;
+    sc_reduce32(&sec);  // reduce in case second round of keys (sendkeys)
+
+    ge_scalarmult_base(&point, &sec);
+    ge_p3_tobytes(&pub, &point);
+
+    return rng;
+  }
+
+  bool crypto_ops::check_key(const public_key &key) {
+    ge_p3 point;
+    return ge_frombytes_vartime(&point, &key) == 0;
+  }
+
+  bool crypto_ops::secret_key_to_public_key(const secret_key &sec, public_key &pub) {
+    ge_p3 point;
+    if (sc_check(&sec) != 0) {
+      return false;
+    }
+    ge_scalarmult_base(&point, &sec);
+    ge_p3_tobytes(&pub, &point);
+    return true;
+  }
+
+  bool crypto_ops::generate_key_derivation(const public_key &key1, const secret_key &key2, key_derivation &derivation) {
+    ge_p3 point;
+    ge_p2 point2;
+    ge_p1p1 point3;
+    assert(sc_check(&key2) == 0);
+    if (ge_frombytes_vartime(&point, &key1) != 0) {
+      return false;
+    }
+    ge_scalarmult(&point2, &key2, &point);
+    ge_mul8(&point3, &point2);
+    ge_p1p1_to_p2(&point2, &point3);
+    ge_tobytes(&derivation, &point2);
+    return true;
+  }
+
+  void crypto_ops::derivation_to_scalar(const key_derivation &derivation, size_t output_index, ec_scalar &res) {
+    struct {
+      key_derivation derivation;
+      char output_index[(sizeof(size_t) * 8 + 6) / 7];
+    } buf;
+    char *end = buf.output_index;
+    buf.derivation = derivation;
+    tools::write_varint(end, output_index);
+    assert(end <= buf.output_index + sizeof buf.output_index);
+    hash_to_scalar(&buf, end - reinterpret_cast<char *>(&buf), res);
+  }
+
+  bool crypto_ops::derive_public_key(const key_derivation &derivation, size_t output_index,
+    const public_key &base, public_key &derived_key) {
+    ec_scalar scalar;
+    ge_p3 point1;
+    ge_p3 point2;
+    ge_cached point3;
+    ge_p1p1 point4;
+    ge_p2 point5;
+    if (ge_frombytes_vartime(&point1, &base) != 0) {
+      return false;
+    }
+    derivation_to_scalar(derivation, output_index, scalar);
+    ge_scalarmult_base(&point2, &scalar);
+    ge_p3_to_cached(&point3, &point2);
+    ge_add(&point4, &point1, &point3);
+    ge_p1p1_to_p2(&point5, &point4);
+    ge_tobytes(&derived_key, &point5);
+    return true;
+  }
+
+  void crypto_ops::derive_secret_key(const key_derivation &derivation, size_t output_index,
+    const secret_key &base, secret_key &derived_key) {
+    ec_scalar scalar;
+    assert(sc_check(&base) == 0);
+    derivation_to_scalar(derivation, output_index, scalar);
+    sc_add(&derived_key, &base, &scalar);
+  }
+
+  bool crypto_ops::derive_subaddress_public_key(const public_key &out_key, const key_derivation &derivation, std::size_t output_index, public_key &derived_key) {
+    ec_scalar scalar;
+    ge_p3 point1;
+    ge_p3 point2;
+    ge_cached point3;
+    ge_p1p1 point4;
+    ge_p2 point5;
+    if (ge_frombytes_vartime(&point1, &out_key) != 0) {
+      return false;
+    }
+    derivation_to_scalar(derivation, output_index, scalar);
+    ge_scalarmult_base(&point2, &scalar);
+    ge_p3_to_cached(&point3, &point2);
+    ge_sub(&point4, &point1, &point3);
+    ge_p1p1_to_p2(&point5, &point4);
+    ge_tobytes(&derived_key, &point5);
+    return true;
+  }
+
+  struct s_comm {
+    hash h;
+    ec_point key;
+    ec_point comm;
+  };
+
+  struct s_comm_2 {
+    hash msg;
+    ec_point D;
+    ec_point X;
+    ec_point Y;
+  };
+
+  void crypto_ops::generate_signature(const hash &prefix_hash, const public_key &pub, const secret_key &sec, signature &sig) {
+    ge_p3 tmp3;
+    ec_scalar k;
+    s_comm buf;
+#if !defined(NDEBUG)
+    {
+      ge_p3 t;
+      public_key t2;
+      assert(sc_check(&sec) == 0);
+      ge_scalarmult_base(&t, &sec);
+      ge_p3_tobytes(&t2, &t);
+      assert(pub == t2);
+    }
+#endif
+    buf.h = prefix_hash;
+    buf.key = pub;
+    random_scalar(k);
+    ge_scalarmult_base(&tmp3, &k);
+    ge_p3_tobytes(&buf.comm, &tmp3);
+    hash_to_scalar(&buf, sizeof(s_comm), sig.c);
+    sc_mulsub(&sig.r, &sig.c, &sec, &k);
+  }
+
+  bool crypto_ops::check_signature(const hash &prefix_hash, const public_key &pub, const signature &sig) {
+    ge_p2 tmp2;
+    ge_p3 tmp3;
+    ec_scalar c;
+    s_comm buf;
+    assert(check_key(pub));
+    buf.h = prefix_hash;
+    buf.key = pub;
+    if (ge_frombytes_vartime(&tmp3, &pub) != 0) {
+      return false;
+    }
+    if (sc_check(&sig.c) != 0 || sc_check(&sig.r) != 0) {
+      return false;
+    }
+    ge_double_scalarmult_base_vartime(&tmp2, &sig.c, &tmp3, &sig.r);
+    ge_tobytes(&buf.comm, &tmp2);
+    hash_to_scalar(&buf, sizeof(s_comm), c);
+    sc_sub(&c, &c, &sig.c);
+    return sc_isnonzero(&c) == 0;
+  }
+
+  void crypto_ops::generate_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional<public_key> &B, const public_key &D, const secret_key &r, signature &sig) {
+    // sanity check
+    ge_p3 R_p3;
+    ge_p3 A_p3;
+    ge_p3 B_p3;
+    ge_p3 D_p3;
+    if (ge_frombytes_vartime(&R_p3, &R) != 0) throw std::runtime_error("tx pubkey is invalid");
+    if (ge_frombytes_vartime(&A_p3, &A) != 0) throw std::runtime_error("recipient view pubkey is invalid");
+    if (B && ge_frombytes_vartime(&B_p3, &*B) != 0) throw std::runtime_error("recipient spend pubkey is invalid");
+    if (ge_frombytes_vartime(&D_p3, &D) != 0) throw std::runtime_error("key derivation is invalid");
+#if !defined(NDEBUG)
+    {
+      assert(sc_check(&r) == 0);
+      // check R == r*G or R == r*B
+      public_key dbg_R;
+      if (B)
+      {
+        ge_p2 dbg_R_p2;
+        ge_scalarmult(&dbg_R_p2, &r, &B_p3);
+        ge_tobytes(&dbg_R, &dbg_R_p2);
+      }
+      else
+      {
+        ge_p3 dbg_R_p3;
+        ge_scalarmult_base(&dbg_R_p3, &r);
+        ge_p3_tobytes(&dbg_R, &dbg_R_p3);
+      }
+      assert(R == dbg_R);
+      // check D == r*A
+      ge_p2 dbg_D_p2;
+      ge_scalarmult(&dbg_D_p2, &r, &A_p3);
+      public_key dbg_D;
+      ge_tobytes(&dbg_D, &dbg_D_p2);
+      assert(D == dbg_D);
+    }
+#endif
+
+    // pick random k
+    ec_scalar k;
+    random_scalar(k);
+    
+    s_comm_2 buf;
+    buf.msg = prefix_hash;
+    buf.D = D;
+
+    if (B)
+    {
+      // compute X = k*B
+      ge_p2 X_p2;
+      ge_scalarmult(&X_p2, &k, &B_p3);
+      ge_tobytes(&buf.X, &X_p2);
+    }
+    else
+    {
+      // compute X = k*G
+      ge_p3 X_p3;
+      ge_scalarmult_base(&X_p3, &k);
+      ge_p3_tobytes(&buf.X, &X_p3);
+    }
+    
+    // compute Y = k*A
+    ge_p2 Y_p2;
+    ge_scalarmult(&Y_p2, &k, &A_p3);
+    ge_tobytes(&buf.Y, &Y_p2);
+
+    // sig.c = Hs(Msg || D || X || Y)
+    hash_to_scalar(&buf, sizeof(buf), sig.c);
+
+    // sig.r = k - sig.c*r
+    sc_mulsub(&sig.r, &sig.c, &r, &k);
+  }
+
+  bool crypto_ops::check_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional<public_key> &B, const public_key &D, const signature &sig) {
+    // sanity check
+    ge_p3 R_p3;
+    ge_p3 A_p3;
+    ge_p3 B_p3;
+    ge_p3 D_p3;
+    if (ge_frombytes_vartime(&R_p3, &R) != 0) return false;
+    if (ge_frombytes_vartime(&A_p3, &A) != 0) return false;
+    if (B && ge_frombytes_vartime(&B_p3, &*B) != 0) return false;
+    if (ge_frombytes_vartime(&D_p3, &D) != 0) return false;
+    if (sc_check(&sig.c) != 0 || sc_check(&sig.r) != 0) return false;
+
+    // compute sig.c*R
+    ge_p3 cR_p3;
+    {
+      ge_p2 cR_p2;
+      ge_scalarmult(&cR_p2, &sig.c, &R_p3);
+      public_key cR;
+      ge_tobytes(&cR, &cR_p2);
+      if (ge_frombytes_vartime(&cR_p3, &cR) != 0) return false;
+    }
+
+    ge_p1p1 X_p1p1;
+    if (B)
+    {
+      // compute X = sig.c*R + sig.r*B
+      ge_p2 rB_p2;
+      ge_scalarmult(&rB_p2, &sig.r, &B_p3);
+      public_key rB;
+      ge_tobytes(&rB, &rB_p2);
+      ge_p3 rB_p3;
+      if (ge_frombytes_vartime(&rB_p3, &rB) != 0) return false;
+      ge_cached rB_cached;
+      ge_p3_to_cached(&rB_cached, &rB_p3);
+      ge_add(&X_p1p1, &cR_p3, &rB_cached);
+    }
+    else
+    {
+      // compute X = sig.c*R + sig.r*G
+      ge_p3 rG_p3;
+      ge_scalarmult_base(&rG_p3, &sig.r);
+      ge_cached rG_cached;
+      ge_p3_to_cached(&rG_cached, &rG_p3);
+      ge_add(&X_p1p1, &cR_p3, &rG_cached);
+    }
+    ge_p2 X_p2;
+    ge_p1p1_to_p2(&X_p2, &X_p1p1);
+
+    // compute sig.c*D
+    ge_p2 cD_p2;
+    ge_scalarmult(&cD_p2, &sig.c, &D_p3);
+
+    // compute sig.r*A
+    ge_p2 rA_p2;
+    ge_scalarmult(&rA_p2, &sig.r, &A_p3);
+
+    // compute Y = sig.c*D + sig.r*A
+    public_key cD;
+    public_key rA;
+    ge_tobytes(&cD, &cD_p2);
+    ge_tobytes(&rA, &rA_p2);
+    ge_p3 cD_p3;
+    ge_p3 rA_p3;
+    if (ge_frombytes_vartime(&cD_p3, &cD) != 0) return false;
+    if (ge_frombytes_vartime(&rA_p3, &rA) != 0) return false;
+    ge_cached rA_cached;
+    ge_p3_to_cached(&rA_cached, &rA_p3);
+    ge_p1p1 Y_p1p1;
+    ge_add(&Y_p1p1, &cD_p3, &rA_cached);
+    ge_p2 Y_p2;
+    ge_p1p1_to_p2(&Y_p2, &Y_p1p1);
+
+    // compute c2 = Hs(Msg || D || X || Y)
+    s_comm_2 buf;
+    buf.msg = prefix_hash;
+    buf.D = D;
+    ge_tobytes(&buf.X, &X_p2);
+    ge_tobytes(&buf.Y, &Y_p2);
+    ec_scalar c2;
+    hash_to_scalar(&buf, sizeof(s_comm_2), c2);
+
+    // test if c2 == sig.c
+    sc_sub(&c2, &c2, &sig.c);
+    return sc_isnonzero(&c2) == 0;
+  }
+
+  static void hash_to_ec(const public_key &key, ge_p3 &res) {
+    hash h;
+    ge_p2 point;
+    ge_p1p1 point2;
+    cn_fast_hash(std::addressof(key), sizeof(public_key), h);
+    ge_fromfe_frombytes_vartime(&point, reinterpret_cast<const unsigned char *>(&h));
+    ge_mul8(&point2, &point);
+    ge_p1p1_to_p3(&res, &point2);
+  }
+
+  void crypto_ops::generate_key_image(const public_key &pub, const secret_key &sec, key_image &image) {
+    ge_p3 point;
+    ge_p2 point2;
+    assert(sc_check(&sec) == 0);
+    hash_to_ec(pub, point);
+    ge_scalarmult(&point2, &sec, &point);
+    ge_tobytes(&image, &point2);
+  }
+
+PUSH_WARNINGS
+DISABLE_VS_WARNINGS(4200)
+  struct ec_point_pair {
+    ec_point a, b;
+  };
+  struct rs_comm {
+    hash h;
+    struct ec_point_pair ab[];
+  };
+POP_WARNINGS
+
+  static inline size_t rs_comm_size(size_t pubs_count) {
+    return sizeof(rs_comm) + pubs_count * sizeof(ec_point_pair);
+  }
+
+  void crypto_ops::generate_ring_signature(const hash &prefix_hash, const key_image &image,
+    const public_key *const *pubs, size_t pubs_count,
+    const secret_key &sec, size_t sec_index,
+    signature *sig) {
+    size_t i;
+    ge_p3 image_unp;
+    ge_dsmp image_pre;
+    ec_scalar sum, k, h;
+    boost::shared_ptr<rs_comm> buf(reinterpret_cast<rs_comm *>(malloc(rs_comm_size(pubs_count))), free);
+    if (!buf)
+      abort();
+    assert(sec_index < pubs_count);
+#if !defined(NDEBUG)
+    {
+      ge_p3 t;
+      public_key t2;
+      key_image t3;
+      assert(sc_check(&sec) == 0);
+      ge_scalarmult_base(&t, &sec);
+      ge_p3_tobytes(&t2, &t);
+      assert(*pubs[sec_index] == t2);
+      generate_key_image(*pubs[sec_index], sec, t3);
+      assert(image == t3);
+      for (i = 0; i < pubs_count; i++) {
+        assert(check_key(*pubs[i]));
+      }
+    }
+#endif
+    if (ge_frombytes_vartime(&image_unp, &image) != 0) {
+      abort();
+    }
+    ge_dsm_precomp(image_pre, &image_unp);
+    sc_0(&sum);
+    buf->h = prefix_hash;
+    for (i = 0; i < pubs_count; i++) {
+      ge_p2 tmp2;
+      ge_p3 tmp3;
+      if (i == sec_index) {
+        random_scalar(k);
+        ge_scalarmult_base(&tmp3, &k);
+        ge_p3_tobytes(&buf->ab[i].a, &tmp3);
+        hash_to_ec(*pubs[i], tmp3);
+        ge_scalarmult(&tmp2, &k, &tmp3);
+        ge_tobytes(&buf->ab[i].b, &tmp2);
+      } else {
+        random_scalar(sig[i].c);
+        random_scalar(sig[i].r);
+        if (ge_frombytes_vartime(&tmp3, &*pubs[i]) != 0) {
+          abort();
+        }
+        ge_double_scalarmult_base_vartime(&tmp2, &sig[i].c, &tmp3, &sig[i].r);
+        ge_tobytes(&buf->ab[i].a, &tmp2);
+        hash_to_ec(*pubs[i], tmp3);
+        ge_double_scalarmult_precomp_vartime(&tmp2, &sig[i].r, &tmp3, &sig[i].c, image_pre);
+        ge_tobytes(&buf->ab[i].b, &tmp2);
+        sc_add(&sum, &sum, &sig[i].c);
+      }
+    }
+    hash_to_scalar(buf.get(), rs_comm_size(pubs_count), h);
+    sc_sub(&sig[sec_index].c, &h, &sum);
+    sc_mulsub(&sig[sec_index].r, &sig[sec_index].c, &sec, &k);
+  }
+
+  bool crypto_ops::check_ring_signature(const hash &prefix_hash, const key_image &image,
+    const public_key *const *pubs, size_t pubs_count,
+    const signature *sig) {
+    size_t i;
+    ge_p3 image_unp;
+    ge_dsmp image_pre;
+    ec_scalar sum, h;
+    boost::shared_ptr<rs_comm> buf(reinterpret_cast<rs_comm *>(malloc(rs_comm_size(pubs_count))), free);
+    if (!buf)
+      return false;
+#if !defined(NDEBUG)
+    for (i = 0; i < pubs_count; i++) {
+      assert(check_key(*pubs[i]));
+    }
+#endif
+    if (ge_frombytes_vartime(&image_unp, &image) != 0) {
+      return false;
+    }
+    ge_dsm_precomp(image_pre, &image_unp);
+    sc_0(&sum);
+    buf->h = prefix_hash;
+    for (i = 0; i < pubs_count; i++) {
+      ge_p2 tmp2;
+      ge_p3 tmp3;
+      if (sc_check(&sig[i].c) != 0 || sc_check(&sig[i].r) != 0) {
+        return false;
+      }
+      if (ge_frombytes_vartime(&tmp3, &*pubs[i]) != 0) {
+        return false;
+      }
+      ge_double_scalarmult_base_vartime(&tmp2, &sig[i].c, &tmp3, &sig[i].r);
+      ge_tobytes(&buf->ab[i].a, &tmp2);
+      hash_to_ec(*pubs[i], tmp3);
+      ge_double_scalarmult_precomp_vartime(&tmp2, &sig[i].r, &tmp3, &sig[i].c, image_pre);
+      ge_tobytes(&buf->ab[i].b, &tmp2);
+      sc_add(&sum, &sum, &sig[i].c);
+    }
+    hash_to_scalar(buf.get(), rs_comm_size(pubs_count), h);
+    sc_sub(&h, &h, &sum);
+    return sc_isnonzero(&h) == 0;
+  }
+}
diff --git a/crypt/monero_crypto/crypto.h b/crypt/monero_crypto/crypto.h
new file mode 100644
index 0000000000..0ce5e6d7a9
--- /dev/null
+++ b/crypt/monero_crypto/crypto.h
@@ -0,0 +1,289 @@
+// 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
+
+#pragma once
+
+#include <cstddef>
+#include <iostream>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/lock_guard.hpp>
+#include <boost/utility/value_init.hpp>
+#include <boost/optional.hpp>
+#include <type_traits>
+#include <vector>
+
+#include "common/pod-class.h"
+#include "common/util.h"
+#include "common/memwipe.h"
+#include "generic-ops.h"
+#include "hex.h"
+#include "span.h"
+#include "hash.h"
+
+namespace crypto {
+
+  extern "C" {
+#include "random.h"
+  }
+
+  extern boost::mutex random_lock;
+
+#pragma pack(push, 1)
+  POD_CLASS ec_point {
+    char data[32];
+  };
+
+  POD_CLASS ec_scalar {
+    char data[32];
+  };
+
+  POD_CLASS public_key: ec_point {
+    friend class crypto_ops;
+  };
+
+  using secret_key = tools::scrubbed<ec_scalar>;
+
+  POD_CLASS public_keyV {
+    std::vector<public_key> keys;
+    int rows;
+  };
+
+  POD_CLASS secret_keyV {
+    std::vector<secret_key> keys;
+    int rows;
+  };
+
+  POD_CLASS public_keyM {
+    int cols;
+    int rows;
+    std::vector<secret_keyV> column_vectors;
+  };
+
+  POD_CLASS key_derivation: ec_point {
+    friend class crypto_ops;
+  };
+
+  POD_CLASS key_image: ec_point {
+    friend class crypto_ops;
+  };
+
+  POD_CLASS signature {
+    ec_scalar c, r;
+    friend class crypto_ops;
+  };
+#pragma pack(pop)
+
+  void hash_to_scalar(const void *data, size_t length, ec_scalar &res);
+
+  static_assert(sizeof(ec_point) == 32 && sizeof(ec_scalar) == 32 &&
+    sizeof(public_key) == 32 && sizeof(secret_key) == 32 &&
+    sizeof(key_derivation) == 32 && sizeof(key_image) == 32 &&
+    sizeof(signature) == 64, "Invalid structure size");
+
+  class crypto_ops {
+    crypto_ops();
+    crypto_ops(const crypto_ops &);
+    void operator=(const crypto_ops &);
+    ~crypto_ops();
+
+    static secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key = secret_key(), bool recover = false);
+    friend secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key, bool recover);
+    static bool check_key(const public_key &);
+    friend bool check_key(const public_key &);
+    static bool secret_key_to_public_key(const secret_key &, public_key &);
+    friend bool secret_key_to_public_key(const secret_key &, public_key &);
+    static bool generate_key_derivation(const public_key &, const secret_key &, key_derivation &);
+    friend bool generate_key_derivation(const public_key &, const secret_key &, key_derivation &);
+    static void derivation_to_scalar(const key_derivation &derivation, size_t output_index, ec_scalar &res);
+    friend void derivation_to_scalar(const key_derivation &derivation, size_t output_index, ec_scalar &res);
+    static bool derive_public_key(const key_derivation &, std::size_t, const public_key &, public_key &);
+    friend bool derive_public_key(const key_derivation &, std::size_t, const public_key &, public_key &);
+    static void derive_secret_key(const key_derivation &, std::size_t, const secret_key &, secret_key &);
+    friend void derive_secret_key(const key_derivation &, std::size_t, const secret_key &, secret_key &);
+    static bool derive_subaddress_public_key(const public_key &, const key_derivation &, std::size_t, public_key &);
+    friend bool derive_subaddress_public_key(const public_key &, const key_derivation &, std::size_t, public_key &);
+    static void generate_signature(const hash &, const public_key &, const secret_key &, signature &);
+    friend void generate_signature(const hash &, const public_key &, const secret_key &, signature &);
+    static bool check_signature(const hash &, const public_key &, const signature &);
+    friend bool check_signature(const hash &, const public_key &, const signature &);
+    static void generate_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const secret_key &, signature &);
+    friend void generate_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const secret_key &, signature &);
+    static bool check_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const signature &);
+    friend bool check_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const signature &);
+    static void generate_key_image(const public_key &, const secret_key &, key_image &);
+    friend void generate_key_image(const public_key &, const secret_key &, key_image &);
+    static void generate_ring_signature(const hash &, const key_image &,
+      const public_key *const *, std::size_t, const secret_key &, std::size_t, signature *);
+    friend void generate_ring_signature(const hash &, const key_image &,
+      const public_key *const *, std::size_t, const secret_key &, std::size_t, signature *);
+    static bool check_ring_signature(const hash &, const key_image &,
+      const public_key *const *, std::size_t, const signature *);
+    friend bool check_ring_signature(const hash &, const key_image &,
+      const public_key *const *, std::size_t, const signature *);
+  };
+
+  /* Generate N random bytes
+   */
+  inline void rand(size_t N, uint8_t *bytes) {
+    boost::lock_guard<boost::mutex> lock(random_lock);
+    generate_random_bytes_not_thread_safe(N, bytes);
+  }
+
+  /* Generate a value filled with random bytes.
+   */
+  template<typename T>
+  typename std::enable_if<std::is_pod<T>::value, T>::type rand() {
+    typename std::remove_cv<T>::type res;
+    boost::lock_guard<boost::mutex> lock(random_lock);
+    generate_random_bytes_not_thread_safe(sizeof(T), &res);
+    return res;
+  }
+
+  /* Generate a new key pair
+   */
+  inline secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key = secret_key(), bool recover = false) {
+    return crypto_ops::generate_keys(pub, sec, recovery_key, recover);
+  }
+
+  /* Check a public key. Returns true if it is valid, false otherwise.
+   */
+  inline bool check_key(const public_key &key) {
+    return crypto_ops::check_key(key);
+  }
+
+  /* Checks a private key and computes the corresponding public key.
+   */
+  inline bool secret_key_to_public_key(const secret_key &sec, public_key &pub) {
+    return crypto_ops::secret_key_to_public_key(sec, pub);
+  }
+
+  /* To generate an ephemeral key used to send money to:
+   * * The sender generates a new key pair, which becomes the transaction key. The public transaction key is included in "extra" field.
+   * * Both the sender and the receiver generate key derivation from the transaction key, the receivers' "view" key and the output index.
+   * * The sender uses key derivation and the receivers' "spend" key to derive an ephemeral public key.
+   * * The receiver can either derive the public key (to check that the transaction is addressed to him) or the private key (to spend the money).
+   */
+  inline bool generate_key_derivation(const public_key &key1, const secret_key &key2, key_derivation &derivation) {
+    return crypto_ops::generate_key_derivation(key1, key2, derivation);
+  }
+  inline bool derive_public_key(const key_derivation &derivation, std::size_t output_index,
+    const public_key &base, public_key &derived_key) {
+    return crypto_ops::derive_public_key(derivation, output_index, base, derived_key);
+  }
+  inline void derivation_to_scalar(const key_derivation &derivation, size_t output_index, ec_scalar &res) {
+    return crypto_ops::derivation_to_scalar(derivation, output_index, res);
+  }
+  inline void derive_secret_key(const key_derivation &derivation, std::size_t output_index,
+    const secret_key &base, secret_key &derived_key) {
+    crypto_ops::derive_secret_key(derivation, output_index, base, derived_key);
+  }
+  inline bool derive_subaddress_public_key(const public_key &out_key, const key_derivation &derivation, std::size_t output_index, public_key &result) {
+    return crypto_ops::derive_subaddress_public_key(out_key, derivation, output_index, result);
+  }
+
+  /* Generation and checking of a standard signature.
+   */
+  inline void generate_signature(const hash &prefix_hash, const public_key &pub, const secret_key &sec, signature &sig) {
+    crypto_ops::generate_signature(prefix_hash, pub, sec, sig);
+  }
+  inline bool check_signature(const hash &prefix_hash, const public_key &pub, const signature &sig) {
+    return crypto_ops::check_signature(prefix_hash, pub, sig);
+  }
+
+  /* Generation and checking of a tx proof; given a tx pubkey R, the recipient's view pubkey A, and the key 
+   * derivation D, the signature proves the knowledge of the tx secret key r such that R=r*G and D=r*A
+   * When the recipient's address is a subaddress, the tx pubkey R is defined as R=r*B where B is the recipient's spend pubkey
+   */
+  inline void generate_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional<public_key> &B, const public_key &D, const secret_key &r, signature &sig) {
+    crypto_ops::generate_tx_proof(prefix_hash, R, A, B, D, r, sig);
+  }
+  inline bool check_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional<public_key> &B, const public_key &D, const signature &sig) {
+    return crypto_ops::check_tx_proof(prefix_hash, R, A, B, D, sig);
+  }
+
+  /* To send money to a key:
+   * * The sender generates an ephemeral key and includes it in transaction output.
+   * * To spend the money, the receiver generates a key image from it.
+   * * Then he selects a bunch of outputs, including the one he spends, and uses them to generate a ring signature.
+   * To check the signature, it is necessary to collect all the keys that were used to generate it. To detect double spends, it is necessary to check that each key image is used at most once.
+   */
+  inline void generate_key_image(const public_key &pub, const secret_key &sec, key_image &image) {
+    crypto_ops::generate_key_image(pub, sec, image);
+  }
+  inline void generate_ring_signature(const hash &prefix_hash, const key_image &image,
+    const public_key *const *pubs, std::size_t pubs_count,
+    const secret_key &sec, std::size_t sec_index,
+    signature *sig) {
+    crypto_ops::generate_ring_signature(prefix_hash, image, pubs, pubs_count, sec, sec_index, sig);
+  }
+  inline bool check_ring_signature(const hash &prefix_hash, const key_image &image,
+    const public_key *const *pubs, std::size_t pubs_count,
+    const signature *sig) {
+    return crypto_ops::check_ring_signature(prefix_hash, image, pubs, pubs_count, sig);
+  }
+
+  /* Variants with vector<const public_key *> parameters.
+   */
+  inline void generate_ring_signature(const hash &prefix_hash, const key_image &image,
+    const std::vector<const public_key *> &pubs,
+    const secret_key &sec, std::size_t sec_index,
+    signature *sig) {
+    generate_ring_signature(prefix_hash, image, pubs.data(), pubs.size(), sec, sec_index, sig);
+  }
+  inline bool check_ring_signature(const hash &prefix_hash, const key_image &image,
+    const std::vector<const public_key *> &pubs,
+    const signature *sig) {
+    return check_ring_signature(prefix_hash, image, pubs.data(), pubs.size(), sig);
+  }
+
+  inline std::ostream &operator <<(std::ostream &o, const crypto::public_key &v) {
+    epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
+  }
+  inline std::ostream &operator <<(std::ostream &o, const crypto::secret_key &v) {
+    epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
+  }
+  inline std::ostream &operator <<(std::ostream &o, const crypto::key_derivation &v) {
+    epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
+  }
+  inline std::ostream &operator <<(std::ostream &o, const crypto::key_image &v) {
+    epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
+  }
+  inline std::ostream &operator <<(std::ostream &o, const crypto::signature &v) {
+    epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
+  }
+
+  const static crypto::public_key null_pkey = boost::value_initialized<crypto::public_key>();
+  const static crypto::secret_key null_skey = boost::value_initialized<crypto::secret_key>();
+}
+
+CRYPTO_MAKE_HASHABLE(public_key)
+CRYPTO_MAKE_HASHABLE(secret_key)
+CRYPTO_MAKE_HASHABLE(key_image)
+CRYPTO_MAKE_COMPARABLE(signature)
diff --git a/crypt/monero_crypto/crypto_ops_builder/Makefile b/crypt/monero_crypto/crypto_ops_builder/Makefile
new file mode 100755
index 0000000000..69b0d3ba37
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/Makefile
@@ -0,0 +1,10 @@
+
+CC=gcc
+CFLAGS=-O2 -Wall
+
+OBJS= fe25519.o ge25519.o sc25519.o sha512-blocks.o sha512-hash.o ed25519.o randombytes.o verify.o
+test: test.o $(OBJS)
+	gcc -o $@ $^
+
+clean:
+	rm -f *.o test
diff --git a/crypt/monero_crypto/crypto_ops_builder/README.md b/crypt/monero_crypto/crypto_ops_builder/README.md
new file mode 100644
index 0000000000..3b87966f53
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/README.md
@@ -0,0 +1,21 @@
+# Monero
+
+Copyright (c) 2014-2017, The Monero Project
+
+## Crypto Ops Builder
+
+In order to ensure the safest implementation of the cryptography in use by Monero we have opted to use the SUPERCOP ref10 implementations wherever possible. The main reason is that SUPERCOP ref10 is old, well tested, and primarily the work of Daniel J. Bernstein and Tanja Lange (among others, see ```designers``` in the ref10 folder). This is particularly relevant, as the team that designed Curve25519 and EdDSA, both of which are at Monero's core, is the same team that created the SUPERCOP implementation.
+
+SUPERCOP ref10 is a fairly secure implementation that focuses on things like constant-time algorithms, to reduce side-channel attacks, sometimes at the cost of performance. However, we consider this a fair trade-off, especially considering that Monero is not that performance sensitive at this stage. In future we may consider faster implementations that still have a measure of safety against side-channel attacks.
+
+## Additional Cryptography
+
+Unfortunately SUPERCOP ref10 does not contain every function Monero's ```crypto-ops``` class needs. Thus there are several new files in the ```ref10CommentedCombined``` folder which allow for the class to be built during compilation. The original ref10 is included in the source tree in order to allow for a comparison to be made between the two, and also to allow for a quick comparison to be made between our in-source copy of SUPERCOP ref10 and an independently downloaded copy.
+
+## Usage
+
+The operation to produce the ```crypto-ops.c``` is automatic and part of the build process. If, however, you want to manually run the build process to verify the output, you can use ```MakeCryptoOps.py```.
+
+## Attribution
+
+The majority of the work we are using is from SUPERCOP, and copyrights and attribution fall to those developers and cryptographers. Beyond that we also include some of the original CryptoNote reference code. The entire build process, and all of the work analysing the functions and figuring out what comes from where, has been done by the Monero Research Lab. Shen Noether, in particular, deserves the bulk of the attribution for that.
diff --git a/crypt/monero_crypto/crypto_ops_builder/api.h b/crypt/monero_crypto/crypto_ops_builder/api.h
new file mode 100755
index 0000000000..60339596d9
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/api.h
@@ -0,0 +1,2 @@
+#define CRYPTO_BYTES 32
+#define CRYPTO_SCALARBYTES 32
diff --git a/crypt/monero_crypto/crypto_ops_builder/crypto-ops-data.c b/crypt/monero_crypto/crypto_ops_builder/crypto-ops-data.c
new file mode 100644
index 0000000000..4bd75b77c6
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/crypto-ops-data.c
@@ -0,0 +1,872 @@
+// 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
+
+#include <stdint.h>
+
+#include "crypto-ops.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 */
+const fe fe_d = {-10913610, 13857413, -15372611, 6949391, 114729, -8787816, -6275908, -3247719, -18696448, -12055116}; /* d */
+const fe fe_sqrtm1 = {-32595792, -7943725, 9377950, 3500415, 12389472, -272473, -25146209, -2005654, 326686, 11406482}; /* sqrt(-1) */
+const fe fe_d2 = {-21827239, -5839606, -30745221, 13898782, 229458, 15978800, -12551817, -6495438, 29715968, 9444199}; /* 2 * d */
+
+/* base[i][j] = (j+1)*256^i*B */
+const ge_precomp ge_base[32][8] = {
+  {
+    {{25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605},
+     {-12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378},
+     {-8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546}},
+    {{-12815894, -12976347, -21581243, 11784320, -25355658, -2750717, -11717903, -3814571, -358445, -10211303},
+     {-21703237, 6903825, 27185491, 6451973, -29577724, -9554005, -15616551, 11189268, -26829678, -5319081},
+     {26966642, 11152617, 32442495, 15396054, 14353839, -12752335, -3128826, -9541118, -15472047, -4166697}},
+    {{15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024},
+     {16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574},
+     {30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357}},
+    {{-17036878, 13921892, 10945806, -6033431, 27105052, -16084379, -28926210, 15006023, 3284568, -6276540},
+     {23599295, -8306047, -11193664, -7687416, 13236774, 10506355, 7464579, 9656445, 13059162, 10374397},
+     {7798556, 16710257, 3033922, 2874086, 28997861, 2835604, 32406664, -3839045, -641708, -101325}},
+    {{10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380},
+     {4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306},
+     {19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942}},
+    {{-15371964, -12862754, 32573250, 4720197, -26436522, 5875511, -19188627, -15224819, -9818940, -12085777},
+     {-8549212, 109983, 15149363, 2178705, 22900618, 4543417, 3044240, -15689887, 1762328, 14866737},
+     {-18199695, -15951423, -10473290, 1707278, -17185920, 3916101, -28236412, 3959421, 27914454, 4383652}},
+    {{5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766},
+     {-30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701},
+     {28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300}},
+    {{14499471, -2729599, -33191113, -4254652, 28494862, 14271267, 30290735, 10876454, -33154098, 2381726},
+     {-7195431, -2655363, -14730155, 462251, -27724326, 3941372, -6236617, 3696005, -32300832, 15351955},
+     {27431194, 8222322, 16448760, -3907995, -18707002, 11938355, -32961401, -2970515, 29551813, 10109425}}
+  }, {
+    {{-13657040, -13155431, -31283750, 11777098, 21447386, 6519384, -2378284, -1627556, 10092783, -4764171},
+     {27939166, 14210322, 4677035, 16277044, -22964462, -12398139, -32508754, 12005538, -17810127, 12803510},
+     {17228999, -15661624, -1233527, 300140, -1224870, -11714777, 30364213, -9038194, 18016357, 4397660}},
+    {{-10958843, -7690207, 4776341, -14954238, 27850028, -15602212, -26619106, 14544525, -17477504, 982639},
+     {29253598, 15796703, -2863982, -9908884, 10057023, 3163536, 7332899, -4120128, -21047696, 9934963},
+     {5793303, 16271923, -24131614, -10116404, 29188560, 1206517, -14747930, 4559895, -30123922, -10897950}},
+    {{-27643952, -11493006, 16282657, -11036493, 28414021, -15012264, 24191034, 4541697, -13338309, 5500568},
+     {12650548, -1497113, 9052871, 11355358, -17680037, -8400164, -17430592, 12264343, 10874051, 13524335},
+     {25556948, -3045990, 714651, 2510400, 23394682, -10415330, 33119038, 5080568, -22528059, 5376628}},
+    {{-26088264, -4011052, -17013699, -3537628, -6726793, 1920897, -22321305, -9447443, 4535768, 1569007},
+     {-2255422, 14606630, -21692440, -8039818, 28430649, 8775819, -30494562, 3044290, 31848280, 12543772},
+     {-22028579, 2943893, -31857513, 6777306, 13784462, -4292203, -27377195, -2062731, 7718482, 14474653}},
+    {{2385315, 2454213, -22631320, 46603, -4437935, -15680415, 656965, -7236665, 24316168, -5253567},
+     {13741529, 10911568, -33233417, -8603737, -20177830, -1033297, 33040651, -13424532, -20729456, 8321686},
+     {21060490, -2212744, 15712757, -4336099, 1639040, 10656336, 23845965, -11874838, -9984458, 608372}},
+    {{-13672732, -15087586, -10889693, -7557059, -6036909, 11305547, 1123968, -6780577, 27229399, 23887},
+     {-23244140, -294205, -11744728, 14712571, -29465699, -2029617, 12797024, -6440308, -1633405, 16678954},
+     {-29500620, 4770662, -16054387, 14001338, 7830047, 9564805, -1508144, -4795045, -17169265, 4904953}},
+    {{24059557, 14617003, 19037157, -15039908, 19766093, -14906429, 5169211, 16191880, 2128236, -4326833},
+     {-16981152, 4124966, -8540610, -10653797, 30336522, -14105247, -29806336, 916033, -6882542, -2986532},
+     {-22630907, 12419372, -7134229, -7473371, -16478904, 16739175, 285431, 2763829, 15736322, 4143876}},
+    {{2379352, 11839345, -4110402, -5988665, 11274298, 794957, 212801, -14594663, 23527084, -16458268},
+     {33431127, -11130478, -17838966, -15626900, 8909499, 8376530, -32625340, 4087881, -15188911, -14416214},
+     {1767683, 7197987, -13205226, -2022635, -13091350, 448826, 5799055, 4357868, -4774191, -16323038}}
+  }, {
+    {{6721966, 13833823, -23523388, -1551314, 26354293, -11863321, 23365147, -3949732, 7390890, 2759800},
+     {4409041, 2052381, 23373853, 10530217, 7676779, -12885954, 21302353, -4264057, 1244380, -12919645},
+     {-4421239, 7169619, 4982368, -2957590, 30256825, -2777540, 14086413, 9208236, 15886429, 16489664}},
+    {{1996075, 10375649, 14346367, 13311202, -6874135, -16438411, -13693198, 398369, -30606455, -712933},
+     {-25307465, 9795880, -2777414, 14878809, -33531835, 14780363, 13348553, 12076947, -30836462, 5113182},
+     {-17770784, 11797796, 31950843, 13929123, -25888302, 12288344, -30341101, -7336386, 13847711, 5387222}},
+    {{-18582163, -3416217, 17824843, -2340966, 22744343, -10442611, 8763061, 3617786, -19600662, 10370991},
+     {20246567, -14369378, 22358229, -543712, 18507283, -10413996, 14554437, -8746092, 32232924, 16763880},
+     {9648505, 10094563, 26416693, 14745928, -30374318, -6472621, 11094161, 15689506, 3140038, -16510092}},
+    {{-16160072, 5472695, 31895588, 4744994, 8823515, 10365685, -27224800, 9448613, -28774454, 366295},
+     {19153450, 11523972, -11096490, -6503142, -24647631, 5420647, 28344573, 8041113, 719605, 11671788},
+     {8678025, 2694440, -6808014, 2517372, 4964326, 11152271, -15432916, -15266516, 27000813, -10195553}},
+    {{-15157904, 7134312, 8639287, -2814877, -7235688, 10421742, 564065, 5336097, 6750977, -14521026},
+     {11836410, -3979488, 26297894, 16080799, 23455045, 15735944, 1695823, -8819122, 8169720, 16220347},
+     {-18115838, 8653647, 17578566, -6092619, -8025777, -16012763, -11144307, -2627664, -5990708, -14166033}},
+    {{-23308498, -10968312, 15213228, -10081214, -30853605, -11050004, 27884329, 2847284, 2655861, 1738395},
+     {-27537433, -14253021, -25336301, -8002780, -9370762, 8129821, 21651608, -3239336, -19087449, -11005278},
+     {1533110, 3437855, 23735889, 459276, 29970501, 11335377, 26030092, 5821408, 10478196, 8544890}},
+    {{32173121, -16129311, 24896207, 3921497, 22579056, -3410854, 19270449, 12217473, 17789017, -3395995},
+     {-30552961, -2228401, -15578829, -10147201, 13243889, 517024, 15479401, -3853233, 30460520, 1052596},
+     {-11614875, 13323618, 32618793, 8175907, -15230173, 12596687, 27491595, -4612359, 3179268, -9478891}},
+    {{31947069, -14366651, -4640583, -15339921, -15125977, -6039709, -14756777, -16411740, 19072640, -9511060},
+     {11685058, 11822410, 3158003, -13952594, 33402194, -4165066, 5977896, -5215017, 473099, 5040608},
+     {-20290863, 8198642, -27410132, 11602123, 1290375, -2799760, 28326862, 1721092, -19558642, -3131606}}
+  }, {
+    {{7881532, 10687937, 7578723, 7738378, -18951012, -2553952, 21820786, 8076149, -27868496, 11538389},
+     {-19935666, 3899861, 18283497, -6801568, -15728660, -11249211, 8754525, 7446702, -5676054, 5797016},
+     {-11295600, -3793569, -15782110, -7964573, 12708869, -8456199, 2014099, -9050574, -2369172, -5877341}},
+    {{-22472376, -11568741, -27682020, 1146375, 18956691, 16640559, 1192730, -3714199, 15123619, 10811505},
+     {14352098, -3419715, -18942044, 10822655, 32750596, 4699007, -70363, 15776356, -28886779, -11974553},
+     {-28241164, -8072475, -4978962, -5315317, 29416931, 1847569, -20654173, -16484855, 4714547, -9600655}},
+    {{15200332, 8368572, 19679101, 15970074, -31872674, 1959451, 24611599, -4543832, -11745876, 12340220},
+     {12876937, -10480056, 33134381, 6590940, -6307776, 14872440, 9613953, 8241152, 15370987, 9608631},
+     {-4143277, -12014408, 8446281, -391603, 4407738, 13629032, -7724868, 15866074, -28210621, -8814099}},
+    {{26660628, -15677655, 8393734, 358047, -7401291, 992988, -23904233, 858697, 20571223, 8420556},
+     {14620715, 13067227, -15447274, 8264467, 14106269, 15080814, 33531827, 12516406, -21574435, -12476749},
+     {236881, 10476226, 57258, -14677024, 6472998, 2466984, 17258519, 7256740, 8791136, 15069930}},
+    {{1276410, -9371918, 22949635, -16322807, -23493039, -5702186, 14711875, 4874229, -30663140, -2331391},
+     {5855666, 4990204, -13711848, 7294284, -7804282, 1924647, -1423175, -7912378, -33069337, 9234253},
+     {20590503, -9018988, 31529744, -7352666, -2706834, 10650548, 31559055, -11609587, 18979186, 13396066}},
+    {{24474287, 4968103, 22267082, 4407354, 24063882, -8325180, -18816887, 13594782, 33514650, 7021958},
+     {-11566906, -6565505, -21365085, 15928892, -26158305, 4315421, -25948728, -3916677, -21480480, 12868082},
+     {-28635013, 13504661, 19988037, -2132761, 21078225, 6443208, -21446107, 2244500, -12455797, -8089383}},
+    {{-30595528, 13793479, -5852820, 319136, -25723172, -6263899, 33086546, 8957937, -15233648, 5540521},
+     {-11630176, -11503902, -8119500, -7643073, 2620056, 1022908, -23710744, -1568984, -16128528, -14962807},
+     {23152971, 775386, 27395463, 14006635, -9701118, 4649512, 1689819, 892185, -11513277, -15205948}},
+    {{9770129, 9586738, 26496094, 4324120, 1556511, -3550024, 27453819, 4763127, -19179614, 5867134},
+     {-32765025, 1927590, 31726409, -4753295, 23962434, -16019500, 27846559, 5931263, -29749703, -16108455},
+     {27461885, -2977536, 22380810, 1815854, -23033753, -3031938, 7283490, -15148073, -19526700, 7734629}}
+  }, {
+    {{-8010264, -9590817, -11120403, 6196038, 29344158, -13430885, 7585295, -3176626, 18549497, 15302069},
+     {-32658337, -6171222, -7672793, -11051681, 6258878, 13504381, 10458790, -6418461, -8872242, 8424746},
+     {24687205, 8613276, -30667046, -3233545, 1863892, -1830544, 19206234, 7134917, -11284482, -828919}},
+    {{11334899, -9218022, 8025293, 12707519, 17523892, -10476071, 10243738, -14685461, -5066034, 16498837},
+     {8911542, 6887158, -9584260, -6958590, 11145641, -9543680, 17303925, -14124238, 6536641, 10543906},
+     {-28946384, 15479763, -17466835, 568876, -1497683, 11223454, -2669190, -16625574, -27235709, 8876771}},
+    {{-25742899, -12566864, -15649966, -846607, -33026686, -796288, -33481822, 15824474, -604426, -9039817},
+     {10330056, 70051, 7957388, -9002667, 9764902, 15609756, 27698697, -4890037, 1657394, 3084098},
+     {10477963, -7470260, 12119566, -13250805, 29016247, -5365589, 31280319, 14396151, -30233575, 15272409}},
+    {{-12288309, 3169463, 28813183, 16658753, 25116432, -5630466, -25173957, -12636138, -25014757, 1950504},
+     {-26180358, 9489187, 11053416, -14746161, -31053720, 5825630, -8384306, -8767532, 15341279, 8373727},
+     {28685821, 7759505, -14378516, -12002860, -31971820, 4079242, 298136, -10232602, -2878207, 15190420}},
+    {{-32932876, 13806336, -14337485, -15794431, -24004620, 10940928, 8669718, 2742393, -26033313, -6875003},
+     {-1580388, -11729417, -25979658, -11445023, -17411874, -10912854, 9291594, -16247779, -12154742, 6048605},
+     {-30305315, 14843444, 1539301, 11864366, 20201677, 1900163, 13934231, 5128323, 11213262, 9168384}},
+    {{-26280513, 11007847, 19408960, -940758, -18592965, -4328580, -5088060, -11105150, 20470157, -16398701},
+     {-23136053, 9282192, 14855179, -15390078, -7362815, -14408560, -22783952, 14461608, 14042978, 5230683},
+     {29969567, -2741594, -16711867, -8552442, 9175486, -2468974, 21556951, 3506042, -5933891, -12449708}},
+    {{-3144746, 8744661, 19704003, 4581278, -20430686, 6830683, -21284170, 8971513, -28539189, 15326563},
+     {-19464629, 10110288, -17262528, -3503892, -23500387, 1355669, -15523050, 15300988, -20514118, 9168260},
+     {-5353335, 4488613, -23803248, 16314347, 7780487, -15638939, -28948358, 9601605, 33087103, -9011387}},
+    {{-19443170, -15512900, -20797467, -12445323, -29824447, 10229461, -27444329, -15000531, -5996870, 15664672},
+     {23294591, -16632613, -22650781, -8470978, 27844204, 11461195, 13099750, -2460356, 18151676, 13417686},
+     {-24722913, -4176517, -31150679, 5988919, -26858785, 6685065, 1661597, -12551441, 15271676, -15452665}}
+  }, {
+    {{11433042, -13228665, 8239631, -5279517, -1985436, -725718, -18698764, 2167544, -6921301, -13440182},
+     {-31436171, 15575146, 30436815, 12192228, -22463353, 9395379, -9917708, -8638997, 12215110, 12028277},
+     {14098400, 6555944, 23007258, 5757252, -15427832, -12950502, 30123440, 4617780, -16900089, -655628}},
+    {{-4026201, -15240835, 11893168, 13718664, -14809462, 1847385, -15819999, 10154009, 23973261, -12684474},
+     {-26531820, -3695990, -1908898, 2534301, -31870557, -16550355, 18341390, -11419951, 32013174, -10103539},
+     {-25479301, 10876443, -11771086, -14625140, -12369567, 1838104, 21911214, 6354752, 4425632, -837822}},
+    {{-10433389, -14612966, 22229858, -3091047, -13191166, 776729, -17415375, -12020462, 4725005, 14044970},
+     {19268650, -7304421, 1555349, 8692754, -21474059, -9910664, 6347390, -1411784, -19522291, -16109756},
+     {-24864089, 12986008, -10898878, -5558584, -11312371, -148526, 19541418, 8180106, 9282262, 10282508}},
+    {{-26205082, 4428547, -8661196, -13194263, 4098402, -14165257, 15522535, 8372215, 5542595, -10702683},
+     {-10562541, 14895633, 26814552, -16673850, -17480754, -2489360, -2781891, 6993761, -18093885, 10114655},
+     {-20107055, -929418, 31422704, 10427861, -7110749, 6150669, -29091755, -11529146, 25953725, -106158}},
+    {{-4234397, -8039292, -9119125, 3046000, 2101609, -12607294, 19390020, 6094296, -3315279, 12831125},
+     {-15998678, 7578152, 5310217, 14408357, -33548620, -224739, 31575954, 6326196, 7381791, -2421839},
+     {-20902779, 3296811, 24736065, -16328389, 18374254, 7318640, 6295303, 8082724, -15362489, 12339664}},
+    {{27724736, 2291157, 6088201, -14184798, 1792727, 5857634, 13848414, 15768922, 25091167, 14856294},
+     {-18866652, 8331043, 24373479, 8541013, -701998, -9269457, 12927300, -12695493, -22182473, -9012899},
+     {-11423429, -5421590, 11632845, 3405020, 30536730, -11674039, -27260765, 13866390, 30146206, 9142070}},
+    {{3924129, -15307516, -13817122, -10054960, 12291820, -668366, -27702774, 9326384, -8237858, 4171294},
+     {-15921940, 16037937, 6713787, 16606682, -21612135, 2790944, 26396185, 3731949, 345228, -5462949},
+     {-21327538, 13448259, 25284571, 1143661, 20614966, -8849387, 2031539, -12391231, -16253183, -13582083}},
+    {{31016211, -16722429, 26371392, -14451233, -5027349, 14854137, 17477601, 3842657, 28012650, -16405420},
+     {-5075835, 9368966, -8562079, -4600902, -15249953, 6970560, -9189873, 16292057, -8867157, 3507940},
+     {29439664, 3537914, 23333589, 6997794, -17555561, -11018068, -15209202, -15051267, -9164929, 6580396}}
+  }, {
+    {{-12185861, -7679788, 16438269, 10826160, -8696817, -6235611, 17860444, -9273846, -2095802, 9304567},
+     {20714564, -4336911, 29088195, 7406487, 11426967, -5095705, 14792667, -14608617, 5289421, -477127},
+     {-16665533, -10650790, -6160345, -13305760, 9192020, -1802462, 17271490, 12349094, 26939669, -3752294}},
+    {{-12889898, 9373458, 31595848, 16374215, 21471720, 13221525, -27283495, -12348559, -3698806, 117887},
+     {22263325, -6560050, 3984570, -11174646, -15114008, -566785, 28311253, 5358056, -23319780, 541964},
+     {16259219, 3261970, 2309254, -15534474, -16885711, -4581916, 24134070, -16705829, -13337066, -13552195}},
+    {{9378160, -13140186, -22845982, -12745264, 28198281, -7244098, -2399684, -717351, 690426, 14876244},
+     {24977353, -314384, -8223969, -13465086, 28432343, -1176353, -13068804, -12297348, -22380984, 6618999},
+     {-1538174, 11685646, 12944378, 13682314, -24389511, -14413193, 8044829, -13817328, 32239829, -5652762}},
+    {{-18603066, 4762990, -926250, 8885304, -28412480, -3187315, 9781647, -10350059, 32779359, 5095274},
+     {-33008130, -5214506, -32264887, -3685216, 9460461, -9327423, -24601656, 14506724, 21639561, -2630236},
+     {-16400943, -13112215, 25239338, 15531969, 3987758, -4499318, -1289502, -6863535, 17874574, 558605}},
+    {{-13600129, 10240081, 9171883, 16131053, -20869254, 9599700, 33499487, 5080151, 2085892, 5119761},
+     {-22205145, -2519528, -16381601, 414691, -25019550, 2170430, 30634760, -8363614, -31999993, -5759884},
+     {-6845704, 15791202, 8550074, -1312654, 29928809, -12092256, 27534430, -7192145, -22351378, 12961482}},
+    {{-24492060, -9570771, 10368194, 11582341, -23397293, -2245287, 16533930, 8206996, -30194652, -5159638},
+     {-11121496, -3382234, 2307366, 6362031, -135455, 8868177, -16835630, 7031275, 7589640, 8945490},
+     {-32152748, 8917967, 6661220, -11677616, -1192060, -15793393, 7251489, -11182180, 24099109, -14456170}},
+    {{5019558, -7907470, 4244127, -14714356, -26933272, 6453165, -19118182, -13289025, -6231896, -10280736},
+     {10853594, 10721687, 26480089, 5861829, -22995819, 1972175, -1866647, -10557898, -3363451, -6441124},
+     {-17002408, 5906790, 221599, -6563147, 7828208, -13248918, 24362661, -2008168, -13866408, 7421392}},
+    {{8139927, -6546497, 32257646, -5890546, 30375719, 1886181, -21175108, 15441252, 28826358, -4123029},
+     {6267086, 9695052, 7709135, -16603597, -32869068, -1886135, 14795160, -7840124, 13746021, -1742048},
+     {28584902, 7787108, -6732942, -15050729, 22846041, -7571236, -3181936, -363524, 4771362, -8419958}}
+  }, {
+    {{24949256, 6376279, -27466481, -8174608, -18646154, -9930606, 33543569, -12141695, 3569627, 11342593},
+     {26514989, 4740088, 27912651, 3697550, 19331575, -11472339, 6809886, 4608608, 7325975, -14801071},
+     {-11618399, -14554430, -24321212, 7655128, -1369274, 5214312, -27400540, 10258390, -17646694, -8186692}},
+    {{11431204, 15823007, 26570245, 14329124, 18029990, 4796082, -31446179, 15580664, 9280358, -3973687},
+     {-160783, -10326257, -22855316, -4304997, -20861367, -13621002, -32810901, -11181622, -15545091, 4387441},
+     {-20799378, 12194512, 3937617, -5805892, -27154820, 9340370, -24513992, 8548137, 20617071, -7482001}},
+    {{-938825, -3930586, -8714311, 16124718, 24603125, -6225393, -13775352, -11875822, 24345683, 10325460},
+     {-19855277, -1568885, -22202708, 8714034, 14007766, 6928528, 16318175, -1010689, 4766743, 3552007},
+     {-21751364, -16730916, 1351763, -803421, -4009670, 3950935, 3217514, 14481909, 10988822, -3994762}},
+    {{15564307, -14311570, 3101243, 5684148, 30446780, -8051356, 12677127, -6505343, -8295852, 13296005},
+     {-9442290, 6624296, -30298964, -11913677, -4670981, -2057379, 31521204, 9614054, -30000824, 12074674},
+     {4771191, -135239, 14290749, -13089852, 27992298, 14998318, -1413936, -1556716, 29832613, -16391035}},
+    {{7064884, -7541174, -19161962, -5067537, -18891269, -2912736, 25825242, 5293297, -27122660, 13101590},
+     {-2298563, 2439670, -7466610, 1719965, -27267541, -16328445, 32512469, -5317593, -30356070, -4190957},
+     {-30006540, 10162316, -33180176, 3981723, -16482138, -13070044, 14413974, 9515896, 19568978, 9628812}},
+    {{33053803, 199357, 15894591, 1583059, 27380243, -4580435, -17838894, -6106839, -6291786, 3437740},
+     {-18978877, 3884493, 19469877, 12726490, 15913552, 13614290, -22961733, 70104, 7463304, 4176122},
+     {-27124001, 10659917, 11482427, -16070381, 12771467, -6635117, -32719404, -5322751, 24216882, 5944158}},
+    {{8894125, 7450974, -2664149, -9765752, -28080517, -12389115, 19345746, 14680796, 11632993, 5847885},
+     {26942781, -2315317, 9129564, -4906607, 26024105, 11769399, -11518837, 6367194, -9727230, 4782140},
+     {19916461, -4828410, -22910704, -11414391, 25606324, -5972441, 33253853, 8220911, 6358847, -1873857}},
+    {{801428, -2081702, 16569428, 11065167, 29875704, 96627, 7908388, -4480480, -13538503, 1387155},
+     {19646058, 5720633, -11416706, 12814209, 11607948, 12749789, 14147075, 15156355, -21866831, 11835260},
+     {19299512, 1155910, 28703737, 14890794, 2925026, 7269399, 26121523, 15467869, -26560550, 5052483}}
+  }, {
+    {{-3017432, 10058206, 1980837, 3964243, 22160966, 12322533, -6431123, -12618185, 12228557, -7003677},
+     {32944382, 14922211, -22844894, 5188528, 21913450, -8719943, 4001465, 13238564, -6114803, 8653815},
+     {22865569, -4652735, 27603668, -12545395, 14348958, 8234005, 24808405, 5719875, 28483275, 2841751}},
+    {{-16420968, -1113305, -327719, -12107856, 21886282, -15552774, -1887966, -315658, 19932058, -12739203},
+     {-11656086, 10087521, -8864888, -5536143, -19278573, -3055912, 3999228, 13239134, -4777469, -13910208},
+     {1382174, -11694719, 17266790, 9194690, -13324356, 9720081, 20403944, 11284705, -14013818, 3093230}},
+    {{16650921, -11037932, -1064178, 1570629, -8329746, 7352753, -302424, 16271225, -24049421, -6691850},
+     {-21911077, -5927941, -4611316, -5560156, -31744103, -10785293, 24123614, 15193618, -21652117, -16739389},
+     {-9935934, -4289447, -25279823, 4372842, 2087473, 10399484, 31870908, 14690798, 17361620, 11864968}},
+    {{-11307610, 6210372, 13206574, 5806320, -29017692, -13967200, -12331205, -7486601, -25578460, -16240689},
+     {14668462, -12270235, 26039039, 15305210, 25515617, 4542480, 10453892, 6577524, 9145645, -6443880},
+     {5974874, 3053895, -9433049, -10385191, -31865124, 3225009, -7972642, 3936128, -5652273, -3050304}},
+    {{30625386, -4729400, -25555961, -12792866, -20484575, 7695099, 17097188, -16303496, -27999779, 1803632},
+     {-3553091, 9865099, -5228566, 4272701, -5673832, -16689700, 14911344, 12196514, -21405489, 7047412},
+     {20093277, 9920966, -11138194, -5343857, 13161587, 12044805, -32856851, 4124601, -32343828, -10257566}},
+    {{-20788824, 14084654, -13531713, 7842147, 19119038, -13822605, 4752377, -8714640, -21679658, 2288038},
+     {-26819236, -3283715, 29965059, 3039786, -14473765, 2540457, 29457502, 14625692, -24819617, 12570232},
+     {-1063558, -11551823, 16920318, 12494842, 1278292, -5869109, -21159943, -3498680, -11974704, 4724943}},
+    {{17960970, -11775534, -4140968, -9702530, -8876562, -1410617, -12907383, -8659932, -29576300, 1903856},
+     {23134274, -14279132, -10681997, -1611936, 20684485, 15770816, -12989750, 3190296, 26955097, 14109738},
+     {15308788, 5320727, -30113809, -14318877, 22902008, 7767164, 29425325, -11277562, 31960942, 11934971}},
+    {{-27395711, 8435796, 4109644, 12222639, -24627868, 14818669, 20638173, 4875028, 10491392, 1379718},
+     {-13159415, 9197841, 3875503, -8936108, -1383712, -5879801, 33518459, 16176658, 21432314, 12180697},
+     {-11787308, 11500838, 13787581, -13832590, -22430679, 10140205, 1465425, 12689540, -10301319, -13872883}}
+  }, {
+    {{5414091, -15386041, -21007664, 9643570, 12834970, 1186149, -2622916, -1342231, 26128231, 6032912},
+     {-26337395, -13766162, 32496025, -13653919, 17847801, -12669156, 3604025, 8316894, -25875034, -10437358},
+     {3296484, 6223048, 24680646, -12246460, -23052020, 5903205, -8862297, -4639164, 12376617, 3188849}},
+    {{29190488, -14659046, 27549113, -1183516, 3520066, -10697301, 32049515, -7309113, -16109234, -9852307},
+     {-14744486, -9309156, 735818, -598978, -20407687, -5057904, 25246078, -15795669, 18640741, -960977},
+     {-6928835, -16430795, 10361374, 5642961, 4910474, 12345252, -31638386, -494430, 10530747, 1053335}},
+    {{-29265967, -14186805, -13538216, -12117373, -19457059, -10655384, -31462369, -2948985, 24018831, 15026644},
+     {-22592535, -3145277, -2289276, 5953843, -13440189, 9425631, 25310643, 13003497, -2314791, -15145616},
+     {-27419985, -603321, -8043984, -1669117, -26092265, 13987819, -27297622, 187899, -23166419, -2531735}},
+    {{-21744398, -13810475, 1844840, 5021428, -10434399, -15911473, 9716667, 16266922, -5070217, 726099},
+     {29370922, -6053998, 7334071, -15342259, 9385287, 2247707, -13661962, -4839461, 30007388, -15823341},
+     {-936379, 16086691, 23751945, -543318, -1167538, -5189036, 9137109, 730663, 9835848, 4555336}},
+    {{-23376435, 1410446, -22253753, -12899614, 30867635, 15826977, 17693930, 544696, -11985298, 12422646},
+     {31117226, -12215734, -13502838, 6561947, -9876867, -12757670, -5118685, -4096706, 29120153, 13924425},
+     {-17400879, -14233209, 19675799, -2734756, -11006962, -5858820, -9383939, -11317700, 7240931, -237388}},
+    {{-31361739, -11346780, -15007447, -5856218, -22453340, -12152771, 1222336, 4389483, 3293637, -15551743},
+     {-16684801, -14444245, 11038544, 11054958, -13801175, -3338533, -24319580, 7733547, 12796905, -6335822},
+     {-8759414, -10817836, -25418864, 10783769, -30615557, -9746811, -28253339, 3647836, 3222231, -11160462}},
+    {{18606113, 1693100, -25448386, -15170272, 4112353, 10045021, 23603893, -2048234, -7550776, 2484985},
+     {9255317, -3131197, -12156162, -1004256, 13098013, -9214866, 16377220, -2102812, -19802075, -3034702},
+     {-22729289, 7496160, -5742199, 11329249, 19991973, -3347502, -31718148, 9936966, -30097688, -10618797}},
+    {{21878590, -5001297, 4338336, 13643897, -3036865, 13160960, 19708896, 5415497, -7360503, -4109293},
+     {27736861, 10103576, 12500508, 8502413, -3413016, -9633558, 10436918, -1550276, -23659143, -8132100},
+     {19492550, -12104365, -29681976, -852630, -3208171, 12403437, 30066266, 8367329, 13243957, 8709688}}
+  }, {
+    {{12015105, 2801261, 28198131, 10151021, 24818120, -4743133, -11194191, -5645734, 5150968, 7274186},
+     {2831366, -12492146, 1478975, 6122054, 23825128, -12733586, 31097299, 6083058, 31021603, -9793610},
+     {-2529932, -2229646, 445613, 10720828, -13849527, -11505937, -23507731, 16354465, 15067285, -14147707}},
+    {{7840942, 14037873, -33364863, 15934016, -728213, -3642706, 21403988, 1057586, -19379462, -12403220},
+     {915865, -16469274, 15608285, -8789130, -24357026, 6060030, -17371319, 8410997, -7220461, 16527025},
+     {32922597, -556987, 20336074, -16184568, 10903705, -5384487, 16957574, 52992, 23834301, 6588044}},
+    {{32752030, 11232950, 3381995, -8714866, 22652988, -10744103, 17159699, 16689107, -20314580, -1305992},
+     {-4689649, 9166776, -25710296, -10847306, 11576752, 12733943, 7924251, -2752281, 1976123, -7249027},
+     {21251222, 16309901, -2983015, -6783122, 30810597, 12967303, 156041, -3371252, 12331345, -8237197}},
+    {{8651614, -4477032, -16085636, -4996994, 13002507, 2950805, 29054427, -5106970, 10008136, -4667901},
+     {31486080, 15114593, -14261250, 12951354, 14369431, -7387845, 16347321, -13662089, 8684155, -10532952},
+     {19443825, 11385320, 24468943, -9659068, -23919258, 2187569, -26263207, -6086921, 31316348, 14219878}},
+    {{-28594490, 1193785, 32245219, 11392485, 31092169, 15722801, 27146014, 6992409, 29126555, 9207390},
+     {32382935, 1110093, 18477781, 11028262, -27411763, -7548111, -4980517, 10843782, -7957600, -14435730},
+     {2814918, 7836403, 27519878, -7868156, -20894015, -11553689, -21494559, 8550130, 28346258, 1994730}},
+    {{-19578299, 8085545, -14000519, -3948622, 2785838, -16231307, -19516951, 7174894, 22628102, 8115180},
+     {-30405132, 955511, -11133838, -15078069, -32447087, -13278079, -25651578, 3317160, -9943017, 930272},
+     {-15303681, -6833769, 28856490, 1357446, 23421993, 1057177, 24091212, -1388970, -22765376, -10650715}},
+    {{-22751231, -5303997, -12907607, -12768866, -15811511, -7797053, -14839018, -16554220, -1867018, 8398970},
+     {-31969310, 2106403, -4736360, 1362501, 12813763, 16200670, 22981545, -6291273, 18009408, -15772772},
+     {-17220923, -9545221, -27784654, 14166835, 29815394, 7444469, 29551787, -3727419, 19288549, 1325865}},
+    {{15100157, -15835752, -23923978, -1005098, -26450192, 15509408, 12376730, -3479146, 33166107, -8042750},
+     {20909231, 13023121, -9209752, 16251778, -5778415, -8094914, 12412151, 10018715, 2213263, -13878373},
+     {32529814, -11074689, 30361439, -16689753, -9135940, 1513226, 22922121, 6382134, -5766928, 8371348}}
+  }, {
+    {{9923462, 11271500, 12616794, 3544722, -29998368, -1721626, 12891687, -8193132, -26442943, 10486144},
+     {-22597207, -7012665, 8587003, -8257861, 4084309, -12970062, 361726, 2610596, -23921530, -11455195},
+     {5408411, -1136691, -4969122, 10561668, 24145918, 14240566, 31319731, -4235541, 19985175, -3436086}},
+    {{-13994457, 16616821, 14549246, 3341099, 32155958, 13648976, -17577068, 8849297, 65030, 8370684},
+     {-8320926, -12049626, 31204563, 5839400, -20627288, -1057277, -19442942, 6922164, 12743482, -9800518},
+     {-2361371, 12678785, 28815050, 4759974, -23893047, 4884717, 23783145, 11038569, 18800704, 255233}},
+    {{-5269658, -1773886, 13957886, 7990715, 23132995, 728773, 13393847, 9066957, 19258688, -14753793},
+     {-2936654, -10827535, -10432089, 14516793, -3640786, 4372541, -31934921, 2209390, -1524053, 2055794},
+     {580882, 16705327, 5468415, -2683018, -30926419, -14696000, -7203346, -8994389, -30021019, 7394435}},
+    {{23838809, 1822728, -15738443, 15242727, 8318092, -3733104, -21672180, -3492205, -4821741, 14799921},
+     {13345610, 9759151, 3371034, -16137791, 16353039, 8577942, 31129804, 13496856, -9056018, 7402518},
+     {2286874, -4435931, -20042458, -2008336, -13696227, 5038122, 11006906, -15760352, 8205061, 1607563}},
+    {{14414086, -8002132, 3331830, -3208217, 22249151, -5594188, 18364661, -2906958, 30019587, -9029278},
+     {-27688051, 1585953, -10775053, 931069, -29120221, -11002319, -14410829, 12029093, 9944378, 8024},
+     {4368715, -3709630, 29874200, -15022983, -20230386, -11410704, -16114594, -999085, -8142388, 5640030}},
+    {{10299610, 13746483, 11661824, 16234854, 7630238, 5998374, 9809887, -16694564, 15219798, -14327783},
+     {27425505, -5719081, 3055006, 10660664, 23458024, 595578, -15398605, -1173195, -18342183, 9742717},
+     {6744077, 2427284, 26042789, 2720740, -847906, 1118974, 32324614, 7406442, 12420155, 1994844}},
+    {{14012521, -5024720, -18384453, -9578469, -26485342, -3936439, -13033478, -10909803, 24319929, -6446333},
+     {16412690, -4507367, 10772641, 15929391, -17068788, -4658621, 10555945, -10484049, -30102368, -4739048},
+     {22397382, -7767684, -9293161, -12792868, 17166287, -9755136, -27333065, 6199366, 21880021, -12250760}},
+    {{-4283307, 5368523, -31117018, 8163389, -30323063, 3209128, 16557151, 8890729, 8840445, 4957760},
+     {-15447727, 709327, -6919446, -10870178, -29777922, 6522332, -21720181, 12130072, -14796503, 5005757},
+     {-2114751, -14308128, 23019042, 15765735, -25269683, 6002752, 10183197, -13239326, -16395286, -2176112}}
+  }, {
+    {{-19025756, 1632005, 13466291, -7995100, -23640451, 16573537, -32013908, -3057104, 22208662, 2000468},
+     {3065073, -1412761, -25598674, -361432, -17683065, -5703415, -8164212, 11248527, -3691214, -7414184},
+     {10379208, -6045554, 8877319, 1473647, -29291284, -12507580, 16690915, 2553332, -3132688, 16400289}},
+    {{15716668, 1254266, -18472690, 7446274, -8448918, 6344164, -22097271, -7285580, 26894937, 9132066},
+     {24158887, 12938817, 11085297, -8177598, -28063478, -4457083, -30576463, 64452, -6817084, -2692882},
+     {13488534, 7794716, 22236231, 5989356, 25426474, -12578208, 2350710, -3418511, -4688006, 2364226}},
+    {{16335052, 9132434, 25640582, 6678888, 1725628, 8517937, -11807024, -11697457, 15445875, -7798101},
+     {29004207, -7867081, 28661402, -640412, -12794003, -7943086, 31863255, -4135540, -278050, -15759279},
+     {-6122061, -14866665, -28614905, 14569919, -10857999, -3591829, 10343412, -6976290, -29828287, -10815811}},
+    {{27081650, 3463984, 14099042, -4517604, 1616303, -6205604, 29542636, 15372179, 17293797, 960709},
+     {20263915, 11434237, -5765435, 11236810, 13505955, -10857102, -16111345, 6493122, -19384511, 7639714},
+     {-2830798, -14839232, 25403038, -8215196, -8317012, -16173699, 18006287, -16043750, 29994677, -15808121}},
+    {{9769828, 5202651, -24157398, -13631392, -28051003, -11561624, -24613141, -13860782, -31184575, 709464},
+     {12286395, 13076066, -21775189, -1176622, -25003198, 4057652, -32018128, -8890874, 16102007, 13205847},
+     {13733362, 5599946, 10557076, 3195751, -5557991, 8536970, -25540170, 8525972, 10151379, 10394400}},
+    {{4024660, -16137551, 22436262, 12276534, -9099015, -2686099, 19698229, 11743039, -33302334, 8934414},
+     {-15879800, -4525240, -8580747, -2934061, 14634845, -698278, -9449077, 3137094, -11536886, 11721158},
+     {17555939, -5013938, 8268606, 2331751, -22738815, 9761013, 9319229, 8835153, -9205489, -1280045}},
+    {{-461409, -7830014, 20614118, 16688288, -7514766, -4807119, 22300304, 505429, 6108462, -6183415},
+     {-5070281, 12367917, -30663534, 3234473, 32617080, -8422642, 29880583, -13483331, -26898490, -7867459},
+     {-31975283, 5726539, 26934134, 10237677, -3173717, -605053, 24199304, 3795095, 7592688, -14992079}},
+    {{21594432, -14964228, 17466408, -4077222, 32537084, 2739898, 6407723, 12018833, -28256052, 4298412},
+     {-20650503, -11961496, -27236275, 570498, 3767144, -1717540, 13891942, -1569194, 13717174, 10805743},
+     {-14676630, -15644296, 15287174, 11927123, 24177847, -8175568, -796431, 14860609, -26938930, -5863836}}
+  }, {
+    {{12962541, 5311799, -10060768, 11658280, 18855286, -7954201, 13286263, -12808704, -4381056, 9882022},
+     {18512079, 11319350, -20123124, 15090309, 18818594, 5271736, -22727904, 3666879, -23967430, -3299429},
+     {-6789020, -3146043, 16192429, 13241070, 15898607, -14206114, -10084880, -6661110, -2403099, 5276065}},
+    {{30169808, -5317648, 26306206, -11750859, 27814964, 7069267, 7152851, 3684982, 1449224, 13082861},
+     {10342826, 3098505, 2119311, 193222, 25702612, 12233820, 23697382, 15056736, -21016438, -8202000},
+     {-33150110, 3261608, 22745853, 7948688, 19370557, -15177665, -26171976, 6482814, -10300080, -11060101}},
+    {{32869458, -5408545, 25609743, 15678670, -10687769, -15471071, 26112421, 2521008, -22664288, 6904815},
+     {29506923, 4457497, 3377935, -9796444, -30510046, 12935080, 1561737, 3841096, -29003639, -6657642},
+     {10340844, -6630377, -18656632, -2278430, 12621151, -13339055, 30878497, -11824370, -25584551, 5181966}},
+    {{25940115, -12658025, 17324188, -10307374, -8671468, 15029094, 24396252, -16450922, -2322852, -12388574},
+     {-21765684, 9916823, -1300409, 4079498, -1028346, 11909559, 1782390, 12641087, 20603771, -6561742},
+     {-18882287, -11673380, 24849422, 11501709, 13161720, -4768874, 1925523, 11914390, 4662781, 7820689}},
+    {{12241050, -425982, 8132691, 9393934, 32846760, -1599620, 29749456, 12172924, 16136752, 15264020},
+     {-10349955, -14680563, -8211979, 2330220, -17662549, -14545780, 10658213, 6671822, 19012087, 3772772},
+     {3753511, -3421066, 10617074, 2028709, 14841030, -6721664, 28718732, -15762884, 20527771, 12988982}},
+    {{-14822485, -5797269, -3707987, 12689773, -898983, -10914866, -24183046, -10564943, 3299665, -12424953},
+     {-16777703, -15253301, -9642417, 4978983, 3308785, 8755439, 6943197, 6461331, -25583147, 8991218},
+     {-17226263, 1816362, -1673288, -6086439, 31783888, -8175991, -32948145, 7417950, -30242287, 1507265}},
+    {{29692663, 6829891, -10498800, 4334896, 20945975, -11906496, -28887608, 8209391, 14606362, -10647073},
+     {-3481570, 8707081, 32188102, 5672294, 22096700, 1711240, -33020695, 9761487, 4170404, -2085325},
+     {-11587470, 14855945, -4127778, -1531857, -26649089, 15084046, 22186522, 16002000, -14276837, -8400798}},
+    {{-4811456, 13761029, -31703877, -2483919, -3312471, 7869047, -7113572, -9620092, 13240845, 10965870},
+     {-7742563, -8256762, -14768334, -13656260, -23232383, 12387166, 4498947, 14147411, 29514390, 4302863},
+     {-13413405, -12407859, 20757302, -13801832, 14785143, 8976368, -5061276, -2144373, 17846988, -13971927}}
+  }, {
+    {{-2244452, -754728, -4597030, -1066309, -6247172, 1455299, -21647728, -9214789, -5222701, 12650267},
+     {-9906797, -16070310, 21134160, 12198166, -27064575, 708126, 387813, 13770293, -19134326, 10958663},
+     {22470984, 12369526, 23446014, -5441109, -21520802, -9698723, -11772496, -11574455, -25083830, 4271862}},
+    {{-25169565, -10053642, -19909332, 15361595, -5984358, 2159192, 75375, -4278529, -32526221, 8469673},
+     {15854970, 4148314, -8893890, 7259002, 11666551, 13824734, -30531198, 2697372, 24154791, -9460943},
+     {15446137, -15806644, 29759747, 14019369, 30811221, -9610191, -31582008, 12840104, 24913809, 9815020}},
+    {{-4709286, -5614269, -31841498, -12288893, -14443537, 10799414, -9103676, 13438769, 18735128, 9466238},
+     {11933045, 9281483, 5081055, -5183824, -2628162, -4905629, -7727821, -10896103, -22728655, 16199064},
+     {14576810, 379472, -26786533, -8317236, -29426508, -10812974, -102766, 1876699, 30801119, 2164795}},
+    {{15995086, 3199873, 13672555, 13712240, -19378835, -4647646, -13081610, -15496269, -13492807, 1268052},
+     {-10290614, -3659039, -3286592, 10948818, 23037027, 3794475, -3470338, -12600221, -17055369, 3565904},
+     {29210088, -9419337, -5919792, -4952785, 10834811, -13327726, -16512102, -10820713, -27162222, -14030531}},
+    {{-13161890, 15508588, 16663704, -8156150, -28349942, 9019123, -29183421, -3769423, 2244111, -14001979},
+     {-5152875, -3800936, -9306475, -6071583, 16243069, 14684434, -25673088, -16180800, 13491506, 4641841},
+     {10813417, 643330, -19188515, -728916, 30292062, -16600078, 27548447, -7721242, 14476989, -12767431}},
+    {{10292079, 9984945, 6481436, 8279905, -7251514, 7032743, 27282937, -1644259, -27912810, 12651324},
+     {-31185513, -813383, 22271204, 11835308, 10201545, 15351028, 17099662, 3988035, 21721536, -3148940},
+     {10202177, -6545839, -31373232, -9574638, -32150642, -8119683, -12906320, 3852694, 13216206, 14842320}},
+    {{-15815640, -10601066, -6538952, -7258995, -6984659, -6581778, -31500847, 13765824, -27434397, 9900184},
+     {14465505, -13833331, -32133984, -14738873, -27443187, 12990492, 33046193, 15796406, -7051866, -8040114},
+     {30924417, -8279620, 6359016, -12816335, 16508377, 9071735, -25488601, 15413635, 9524356, -7018878}},
+    {{12274201, -13175547, 32627641, -1785326, 6736625, 13267305, 5237659, -5109483, 15663516, 4035784},
+     {-2951309, 8903985, 17349946, 601635, -16432815, -4612556, -13732739, -15889334, -22258478, 4659091},
+     {-16916263, -4952973, -30393711, -15158821, 20774812, 15897498, 5736189, 15026997, -2178256, -13455585}}
+  }, {
+    {{-8858980, -2219056, 28571666, -10155518, -474467, -10105698, -3801496, 278095, 23440562, -290208},
+     {10226241, -5928702, 15139956, 120818, -14867693, 5218603, 32937275, 11551483, -16571960, -7442864},
+     {17932739, -12437276, -24039557, 10749060, 11316803, 7535897, 22503767, 5561594, -3646624, 3898661}},
+    {{7749907, -969567, -16339731, -16464, -25018111, 15122143, -1573531, 7152530, 21831162, 1245233},
+     {26958459, -14658026, 4314586, 8346991, -5677764, 11960072, -32589295, -620035, -30402091, -16716212},
+     {-12165896, 9166947, 33491384, 13673479, 29787085, 13096535, 6280834, 14587357, -22338025, 13987525}},
+    {{-24349909, 7778775, 21116000, 15572597, -4833266, -5357778, -4300898, -5124639, -7469781, -2858068},
+     {9681908, -6737123, -31951644, 13591838, -6883821, 386950, 31622781, 6439245, -14581012, 4091397},
+     {-8426427, 1470727, -28109679, -1596990, 3978627, -5123623, -19622683, 12092163, 29077877, -14741988}},
+    {{5269168, -6859726, -13230211, -8020715, 25932563, 1763552, -5606110, -5505881, -20017847, 2357889},
+     {32264008, -15407652, -5387735, -1160093, -2091322, -3946900, 23104804, -12869908, 5727338, 189038},
+     {14609123, -8954470, -6000566, -16622781, -14577387, -7743898, -26745169, 10942115, -25888931, -14884697}},
+    {{20513500, 5557931, -15604613, 7829531, 26413943, -2019404, -21378968, 7471781, 13913677, -5137875},
+     {-25574376, 11967826, 29233242, 12948236, -6754465, 4713227, -8940970, 14059180, 12878652, 8511905},
+     {-25656801, 3393631, -2955415, -7075526, -2250709, 9366908, -30223418, 6812974, 5568676, -3127656}},
+    {{11630004, 12144454, 2116339, 13606037, 27378885, 15676917, -17408753, -13504373, -14395196, 8070818},
+     {27117696, -10007378, -31282771, -5570088, 1127282, 12772488, -29845906, 10483306, -11552749, -1028714},
+     {10637467, -5688064, 5674781, 1072708, -26343588, -6982302, -1683975, 9177853, -27493162, 15431203}},
+    {{20525145, 10892566, -12742472, 12779443, -29493034, 16150075, -28240519, 14943142, -15056790, -7935931},
+     {-30024462, 5626926, -551567, -9981087, 753598, 11981191, 25244767, -3239766, -3356550, 9594024},
+     {-23752644, 2636870, -5163910, -10103818, 585134, 7877383, 11345683, -6492290, 13352335, -10977084}},
+    {{-1931799, -5407458, 3304649, -12884869, 17015806, -4877091, -29783850, -7752482, -13215537, -319204},
+     {20239939, 6607058, 6203985, 3483793, -18386976, -779229, -20723742, 15077870, -22750759, 14523817},
+     {27406042, -6041657, 27423596, -4497394, 4996214, 10002360, -28842031, -4545494, -30172742, -4805667}}
+  }, {
+    {{11374242, 12660715, 17861383, -12540833, 10935568, 1099227, -13886076, -9091740, -27727044, 11358504},
+     {-12730809, 10311867, 1510375, 10778093, -2119455, -9145702, 32676003, 11149336, -26123651, 4985768},
+     {-19096303, 341147, -6197485, -239033, 15756973, -8796662, -983043, 13794114, -19414307, -15621255}},
+    {{6490081, 11940286, 25495923, -7726360, 8668373, -8751316, 3367603, 6970005, -1691065, -9004790},
+     {1656497, 13457317, 15370807, 6364910, 13605745, 8362338, -19174622, -5475723, -16796596, -5031438},
+     {-22273315, -13524424, -64685, -4334223, -18605636, -10921968, -20571065, -7007978, -99853, -10237333}},
+    {{17747465, 10039260, 19368299, -4050591, -20630635, -16041286, 31992683, -15857976, -29260363, -5511971},
+     {31932027, -4986141, -19612382, 16366580, 22023614, 88450, 11371999, -3744247, 4882242, -10626905},
+     {29796507, 37186, 19818052, 10115756, -11829032, 3352736, 18551198, 3272828, -5190932, -4162409}},
+    {{12501286, 4044383, -8612957, -13392385, -32430052, 5136599, -19230378, -3529697, 330070, -3659409},
+     {6384877, 2899513, 17807477, 7663917, -2358888, 12363165, 25366522, -8573892, -271295, 12071499},
+     {-8365515, -4042521, 25133448, -4517355, -6211027, 2265927, -32769618, 1936675, -5159697, 3829363}},
+    {{28425966, -5835433, -577090, -4697198, -14217555, 6870930, 7921550, -6567787, 26333140, 14267664},
+     {-11067219, 11871231, 27385719, -10559544, -4585914, -11189312, 10004786, -8709488, -21761224, 8930324},
+     {-21197785, -16396035, 25654216, -1725397, 12282012, 11008919, 1541940, 4757911, -26491501, -16408940}},
+    {{13537262, -7759490, -20604840, 10961927, -5922820, -13218065, -13156584, 6217254, -15943699, 13814990},
+     {-17422573, 15157790, 18705543, 29619, 24409717, -260476, 27361681, 9257833, -1956526, -1776914},
+     {-25045300, -10191966, 15366585, 15166509, -13105086, 8423556, -29171540, 12361135, -18685978, 4578290}},
+    {{24579768, 3711570, 1342322, -11180126, -27005135, 14124956, -22544529, 14074919, 21964432, 8235257},
+     {-6528613, -2411497, 9442966, -5925588, 12025640, -1487420, -2981514, -1669206, 13006806, 2355433},
+     {-16304899, -13605259, -6632427, -5142349, 16974359, -10911083, 27202044, 1719366, 1141648, -12796236}},
+    {{-12863944, -13219986, -8318266, -11018091, -6810145, -4843894, 13475066, -3133972, 32674895, 13715045},
+     {11423335, -5468059, 32344216, 8962751, 24989809, 9241752, -13265253, 16086212, -28740881, -15642093},
+     {-1409668, 12530728, -6368726, 10847387, 19531186, -14132160, -11709148, 7791794, -27245943, 4383347}}
+  }, {
+    {{-28970898, 5271447, -1266009, -9736989, -12455236, 16732599, -4862407, -4906449, 27193557, 6245191},
+     {-15193956, 5362278, -1783893, 2695834, 4960227, 12840725, 23061898, 3260492, 22510453, 8577507},
+     {-12632451, 11257346, -32692994, 13548177, -721004, 10879011, 31168030, 13952092, -29571492, -3635906}},
+    {{3877321, -9572739, 32416692, 5405324, -11004407, -13656635, 3759769, 11935320, 5611860, 8164018},
+     {-16275802, 14667797, 15906460, 12155291, -22111149, -9039718, 32003002, -8832289, 5773085, -8422109},
+     {-23788118, -8254300, 1950875, 8937633, 18686727, 16459170, -905725, 12376320, 31632953, 190926}},
+    {{-24593607, -16138885, -8423991, 13378746, 14162407, 6901328, -8288749, 4508564, -25341555, -3627528},
+     {8884438, -5884009, 6023974, 10104341, -6881569, -4941533, 18722941, -14786005, -1672488, 827625},
+     {-32720583, -16289296, -32503547, 7101210, 13354605, 2659080, -1800575, -14108036, -24878478, 1541286}},
+    {{2901347, -1117687, 3880376, -10059388, -17620940, -3612781, -21802117, -3567481, 20456845, -1885033},
+     {27019610, 12299467, -13658288, -1603234, -12861660, -4861471, -19540150, -5016058, 29439641, 15138866},
+     {21536104, -6626420, -32447818, -10690208, -22408077, 5175814, -5420040, -16361163, 7779328, 109896}},
+    {{30279744, 14648750, -8044871, 6425558, 13639621, -743509, 28698390, 12180118, 23177719, -554075},
+     {26572847, 3405927, -31701700, 12890905, -19265668, 5335866, -6493768, 2378492, 4439158, -13279347},
+     {-22716706, 3489070, -9225266, -332753, 18875722, -1140095, 14819434, -12731527, -17717757, -5461437}},
+    {{-5056483, 16566551, 15953661, 3767752, -10436499, 15627060, -820954, 2177225, 8550082, -15114165},
+     {-18473302, 16596775, -381660, 15663611, 22860960, 15585581, -27844109, -3582739, -23260460, -8428588},
+     {-32480551, 15707275, -8205912, -5652081, 29464558, 2713815, -22725137, 15860482, -21902570, 1494193}},
+    {{-19562091, -14087393, -25583872, -9299552, 13127842, 759709, 21923482, 16529112, 8742704, 12967017},
+     {-28464899, 1553205, 32536856, -10473729, -24691605, -406174, -8914625, -2933896, -29903758, 15553883},
+     {21877909, 3230008, 9881174, 10539357, -4797115, 2841332, 11543572, 14513274, 19375923, -12647961}},
+    {{8832269, -14495485, 13253511, 5137575, 5037871, 4078777, 24880818, -6222716, 2862653, 9455043},
+     {29306751, 5123106, 20245049, -14149889, 9592566, 8447059, -2077124, -2990080, 15511449, 4789663},
+     {-20679756, 7004547, 8824831, -9434977, -4045704, -3750736, -5754762, 108893, 23513200, 16652362}}
+  }, {
+    {{-33256173, 4144782, -4476029, -6579123, 10770039, -7155542, -6650416, -12936300, -18319198, 10212860},
+     {2756081, 8598110, 7383731, -6859892, 22312759, -1105012, 21179801, 2600940, -9988298, -12506466},
+     {-24645692, 13317462, -30449259, -15653928, 21365574, -10869657, 11344424, 864440, -2499677, -16710063}},
+    {{-26432803, 6148329, -17184412, -14474154, 18782929, -275997, -22561534, 211300, 2719757, 4940997},
+     {-1323882, 3911313, -6948744, 14759765, -30027150, 7851207, 21690126, 8518463, 26699843, 5276295},
+     {-13149873, -6429067, 9396249, 365013, 24703301, -10488939, 1321586, 149635, -15452774, 7159369}},
+    {{9987780, -3404759, 17507962, 9505530, 9731535, -2165514, 22356009, 8312176, 22477218, -8403385},
+     {18155857, -16504990, 19744716, 9006923, 15154154, -10538976, 24256460, -4864995, -22548173, 9334109},
+     {2986088, -4911893, 10776628, -3473844, 10620590, -7083203, -21413845, 14253545, -22587149, 536906}},
+    {{4377756, 8115836, 24567078, 15495314, 11625074, 13064599, 7390551, 10589625, 10838060, -15420424},
+     {-19342404, 867880, 9277171, -3218459, -14431572, -1986443, 19295826, -15796950, 6378260, 699185},
+     {7895026, 4057113, -7081772, -13077756, -17886831, -323126, -716039, 15693155, -5045064, -13373962}},
+    {{-7737563, -5869402, -14566319, -7406919, 11385654, 13201616, 31730678, -10962840, -3918636, -9669325},
+     {10188286, -15770834, -7336361, 13427543, 22223443, 14896287, 30743455, 7116568, -21786507, 5427593},
+     {696102, 13206899, 27047647, -10632082, 15285305, -9853179, 10798490, -4578720, 19236243, 12477404}},
+    {{-11229439, 11243796, -17054270, -8040865, -788228, -8167967, -3897669, 11180504, -23169516, 7733644},
+     {17800790, -14036179, -27000429, -11766671, 23887827, 3149671, 23466177, -10538171, 10322027, 15313801},
+     {26246234, 11968874, 32263343, -5468728, 6830755, -13323031, -15794704, -101982, -24449242, 10890804}},
+    {{-31365647, 10271363, -12660625, -6267268, 16690207, -13062544, -14982212, 16484931, 25180797, -5334884},
+     {-586574, 10376444, -32586414, -11286356, 19801893, 10997610, 2276632, 9482883, 316878, 13820577},
+     {-9882808, -4510367, -2115506, 16457136, -11100081, 11674996, 30756178, -7515054, 30696930, -3712849}},
+    {{32988917, -9603412, 12499366, 7910787, -10617257, -11931514, -7342816, -9985397, -32349517, 7392473},
+     {-8855661, 15927861, 9866406, -3649411, -2396914, -16655781, -30409476, -9134995, 25112947, -2926644},
+     {-2504044, -436966, 25621774, -5678772, 15085042, -5479877, -24884878, -13526194, 5537438, -13914319}}
+  }, {
+    {{-11225584, 2320285, -9584280, 10149187, -33444663, 5808648, -14876251, -1729667, 31234590, 6090599},
+     {-9633316, 116426, 26083934, 2897444, -6364437, -2688086, 609721, 15878753, -6970405, -9034768},
+     {-27757857, 247744, -15194774, -9002551, 23288161, -10011936, -23869595, 6503646, 20650474, 1804084}},
+    {{-27589786, 15456424, 8972517, 8469608, 15640622, 4439847, 3121995, -10329713, 27842616, -202328},
+     {-15306973, 2839644, 22530074, 10026331, 4602058, 5048462, 28248656, 5031932, -11375082, 12714369},
+     {20807691, -7270825, 29286141, 11421711, -27876523, -13868230, -21227475, 1035546, -19733229, 12796920}},
+    {{12076899, -14301286, -8785001, -11848922, -25012791, 16400684, -17591495, -12899438, 3480665, -15182815},
+     {-32361549, 5457597, 28548107, 7833186, 7303070, -11953545, -24363064, -15921875, -33374054, 2771025},
+     {-21389266, 421932, 26597266, 6860826, 22486084, -6737172, -17137485, -4210226, -24552282, 15673397}},
+    {{-20184622, 2338216, 19788685, -9620956, -4001265, -8740893, -20271184, 4733254, 3727144, -12934448},
+     {6120119, 814863, -11794402, -622716, 6812205, -15747771, 2019594, 7975683, 31123697, -10958981},
+     {30069250, -11435332, 30434654, 2958439, 18399564, -976289, 12296869, 9204260, -16432438, 9648165}},
+    {{32705432, -1550977, 30705658, 7451065, -11805606, 9631813, 3305266, 5248604, -26008332, -11377501},
+     {17219865, 2375039, -31570947, -5575615, -19459679, 9219903, 294711, 15298639, 2662509, -16297073},
+     {-1172927, -7558695, -4366770, -4287744, -21346413, -8434326, 32087529, -1222777, 32247248, -14389861}},
+    {{14312628, 1221556, 17395390, -8700143, -4945741, -8684635, -28197744, -9637817, -16027623, -13378845},
+     {-1428825, -9678990, -9235681, 6549687, -7383069, -468664, 23046502, 9803137, 17597934, 2346211},
+     {18510800, 15337574, 26171504, 981392, -22241552, 7827556, -23491134, -11323352, 3059833, -11782870}},
+    {{10141598, 6082907, 17829293, -1947643, 9830092, 13613136, -25556636, -5544586, -33502212, 3592096},
+     {33114168, -15889352, -26525686, -13343397, 33076705, 8716171, 1151462, 1521897, -982665, -6837803},
+     {-32939165, -4255815, 23947181, -324178, -33072974, -12305637, -16637686, 3891704, 26353178, 693168}},
+    {{30374239, 1595580, -16884039, 13186931, 4600344, 406904, 9585294, -400668, 31375464, 14369965},
+     {-14370654, -7772529, 1510301, 6434173, -18784789, -6262728, 32732230, -13108839, 17901441, 16011505},
+     {18171223, -11934626, -12500402, 15197122, -11038147, -15230035, -19172240, -16046376, 8764035, 12309598}}
+  }, {
+    {{5975908, -5243188, -19459362, -9681747, -11541277, 14015782, -23665757, 1228319, 17544096, -10593782},
+     {5811932, -1715293, 3442887, -2269310, -18367348, -8359541, -18044043, -15410127, -5565381, 12348900},
+     {-31399660, 11407555, 25755363, 6891399, -3256938, 14872274, -24849353, 8141295, -10632534, -585479}},
+    {{-12675304, 694026, -5076145, 13300344, 14015258, -14451394, -9698672, -11329050, 30944593, 1130208},
+     {8247766, -6710942, -26562381, -7709309, -14401939, -14648910, 4652152, 2488540, 23550156, -271232},
+     {17294316, -3788438, 7026748, 15626851, 22990044, 113481, 2267737, -5908146, -408818, -137719}},
+    {{16091085, -16253926, 18599252, 7340678, 2137637, -1221657, -3364161, 14550936, 3260525, -7166271},
+     {-4910104, -13332887, 18550887, 10864893, -16459325, -7291596, -23028869, -13204905, -12748722, 2701326},
+     {-8574695, 16099415, 4629974, -16340524, -20786213, -6005432, -10018363, 9276971, 11329923, 1862132}},
+    {{14763076, -15903608, -30918270, 3689867, 3511892, 10313526, -21951088, 12219231, -9037963, -940300},
+     {8894987, -3446094, 6150753, 3013931, 301220, 15693451, -31981216, -2909717, -15438168, 11595570},
+     {15214962, 3537601, -26238722, -14058872, 4418657, -15230761, 13947276, 10730794, -13489462, -4363670}},
+    {{-2538306, 7682793, 32759013, 263109, -29984731, -7955452, -22332124, -10188635, 977108, 699994},
+     {-12466472, 4195084, -9211532, 550904, -15565337, 12917920, 19118110, -439841, -30534533, -14337913},
+     {31788461, -14507657, 4799989, 7372237, 8808585, -14747943, 9408237, -10051775, 12493932, -5409317}},
+    {{-25680606, 5260744, -19235809, -6284470, -3695942, 16566087, 27218280, 2607121, 29375955, 6024730},
+     {842132, -2794693, -4763381, -8722815, 26332018, -12405641, 11831880, 6985184, -9940361, 2854096},
+     {-4847262, -7969331, 2516242, -5847713, 9695691, -7221186, 16512645, 960770, 12121869, 16648078}},
+    {{-15218652, 14667096, -13336229, 2013717, 30598287, -464137, -31504922, -7882064, 20237806, 2838411},
+     {-19288047, 4453152, 15298546, -16178388, 22115043, -15972604, 12544294, -13470457, 1068881, -12499905},
+     {-9558883, -16518835, 33238498, 13506958, 30505848, -1114596, -8486907, -2630053, 12521378, 4845654}},
+    {{-28198521, 10744108, -2958380, 10199664, 7759311, -13088600, 3409348, -873400, -6482306, -12885870},
+     {-23561822, 6230156, -20382013, 10655314, -24040585, -11621172, 10477734, -1240216, -3113227, 13974498},
+     {12966261, 15550616, -32038948, -1615346, 21025980, -629444, 5642325, 7188737, 18895762, 12629579}}
+  }, {
+    {{14741879, -14946887, 22177208, -11721237, 1279741, 8058600, 11758140, 789443, 32195181, 3895677},
+     {10758205, 15755439, -4509950, 9243698, -4879422, 6879879, -2204575, -3566119, -8982069, 4429647},
+     {-2453894, 15725973, -20436342, -10410672, -5803908, -11040220, -7135870, -11642895, 18047436, -15281743}},
+    {{-25173001, -11307165, 29759956, 11776784, -22262383, -15820455, 10993114, -12850837, -17620701, -9408468},
+     {21987233, 700364, -24505048, 14972008, -7774265, -5718395, 32155026, 2581431, -29958985, 8773375},
+     {-25568350, 454463, -13211935, 16126715, 25240068, 8594567, 20656846, 12017935, -7874389, -13920155}},
+    {{6028182, 6263078, -31011806, -11301710, -818919, 2461772, -31841174, -5468042, -1721788, -2776725},
+     {-12278994, 16624277, 987579, -5922598, 32908203, 1248608, 7719845, -4166698, 28408820, 6816612},
+     {-10358094, -8237829, 19549651, -12169222, 22082623, 16147817, 20613181, 13982702, -10339570, 5067943}},
+    {{-30505967, -3821767, 12074681, 13582412, -19877972, 2443951, -19719286, 12746132, 5331210, -10105944},
+     {30528811, 3601899, -1957090, 4619785, -27361822, -15436388, 24180793, -12570394, 27679908, -1648928},
+     {9402404, -13957065, 32834043, 10838634, -26580150, -13237195, 26653274, -8685565, 22611444, -12715406}},
+    {{22190590, 1118029, 22736441, 15130463, -30460692, -5991321, 19189625, -4648942, 4854859, 6622139},
+     {-8310738, -2953450, -8262579, -3388049, -10401731, -271929, 13424426, -3567227, 26404409, 13001963},
+     {-31241838, -15415700, -2994250, 8939346, 11562230, -12840670, -26064365, -11621720, -15405155, 11020693}},
+    {{1866042, -7949489, -7898649, -10301010, 12483315, 13477547, 3175636, -12424163, 28761762, 1406734},
+     {-448555, -1777666, 13018551, 3194501, -9580420, -11161737, 24760585, -4347088, 25577411, -13378680},
+     {-24290378, 4759345, -690653, -1852816, 2066747, 10693769, -29595790, 9884936, -9368926, 4745410}},
+    {{-9141284, 6049714, -19531061, -4341411, -31260798, 9944276, -15462008, -11311852, 10931924, -11931931},
+     {-16561513, 14112680, -8012645, 4817318, -8040464, -11414606, -22853429, 10856641, -20470770, 13434654},
+     {22759489, -10073434, -16766264, -1871422, 13637442, -10168091, 1765144, -12654326, 28445307, -5364710}},
+    {{29875063, 12493613, 2795536, -3786330, 1710620, 15181182, -10195717, -8788675, 9074234, 1167180},
+     {-26205683, 11014233, -9842651, -2635485, -26908120, 7532294, -18716888, -9535498, 3843903, 9367684},
+     {-10969595, -6403711, 9591134, 9582310, 11349256, 108879, 16235123, 8601684, -139197, 4242895}}
+  }, {
+    {{22092954, -13191123, -2042793, -11968512, 32186753, -11517388, -6574341, 2470660, -27417366, 16625501},
+     {-11057722, 3042016, 13770083, -9257922, 584236, -544855, -7770857, 2602725, -27351616, 14247413},
+     {6314175, -10264892, -32772502, 15957557, -10157730, 168750, -8618807, 14290061, 27108877, -1180880}},
+    {{-8586597, -7170966, 13241782, 10960156, -32991015, -13794596, 33547976, -11058889, -27148451, 981874},
+     {22833440, 9293594, -32649448, -13618667, -9136966, 14756819, -22928859, -13970780, -10479804, -16197962},
+     {-7768587, 3326786, -28111797, 10783824, 19178761, 14905060, 22680049, 13906969, -15933690, 3797899}},
+    {{21721356, -4212746, -12206123, 9310182, -3882239, -13653110, 23740224, -2709232, 20491983, -8042152},
+     {9209270, -15135055, -13256557, -6167798, -731016, 15289673, 25947805, 15286587, 30997318, -6703063},
+     {7392032, 16618386, 23946583, -8039892, -13265164, -1533858, -14197445, -2321576, 17649998, -250080}},
+    {{-9301088, -14193827, 30609526, -3049543, -25175069, -1283752, -15241566, -9525724, -2233253, 7662146},
+     {-17558673, 1763594, -33114336, 15908610, -30040870, -12174295, 7335080, -8472199, -3174674, 3440183},
+     {-19889700, -5977008, -24111293, -9688870, 10799743, -16571957, 40450, -4431835, 4862400, 1133}},
+    {{-32856209, -7873957, -5422389, 14860950, -16319031, 7956142, 7258061, 311861, -30594991, -7379421},
+     {-3773428, -1565936, 28985340, 7499440, 24445838, 9325937, 29727763, 16527196, 18278453, 15405622},
+     {-4381906, 8508652, -19898366, -3674424, -5984453, 15149970, -13313598, 843523, -21875062, 13626197}},
+    {{2281448, -13487055, -10915418, -2609910, 1879358, 16164207, -10783882, 3953792, 13340839, 15928663},
+     {31727126, -7179855, -18437503, -8283652, 2875793, -16390330, -25269894, -7014826, -23452306, 5964753},
+     {4100420, -5959452, -17179337, 6017714, -18705837, 12227141, -26684835, 11344144, 2538215, -7570755}},
+    {{-9433605, 6123113, 11159803, -2156608, 30016280, 14966241, -20474983, 1485421, -629256, -15958862},
+     {-26804558, 4260919, 11851389, 9658551, -32017107, 16367492, -20205425, -13191288, 11659922, -11115118},
+     {26180396, 10015009, -30844224, -8581293, 5418197, 9480663, 2231568, -10170080, 33100372, -1306171}},
+    {{15121113, -5201871, -10389905, 15427821, -27509937, -15992507, 21670947, 4486675, -5931810, -14466380},
+     {16166486, -9483733, -11104130, 6023908, -31926798, -1364923, 2340060, -16254968, -10735770, -10039824},
+     {28042865, -3557089, -12126526, 12259706, -3717498, -6945899, 6766453, -8689599, 18036436, 5803270}}
+  }, {
+    {{-817581, 6763912, 11803561, 1585585, 10958447, -2671165, 23855391, 4598332, -6159431, -14117438},
+     {-31031306, -14256194, 17332029, -2383520, 31312682, -5967183, 696309, 50292, -20095739, 11763584},
+     {-594563, -2514283, -32234153, 12643980, 12650761, 14811489, 665117, -12613632, -19773211, -10713562}},
+    {{30464590, -11262872, -4127476, -12734478, 19835327, -7105613, -24396175, 2075773, -17020157, 992471},
+     {18357185, -6994433, 7766382, 16342475, -29324918, 411174, 14578841, 8080033, -11574335, -10601610},
+     {19598397, 10334610, 12555054, 2555664, 18821899, -10339780, 21873263, 16014234, 26224780, 16452269}},
+    {{-30223925, 5145196, 5944548, 16385966, 3976735, 2009897, -11377804, -7618186, -20533829, 3698650},
+     {14187449, 3448569, -10636236, -10810935, -22663880, -3433596, 7268410, -10890444, 27394301, 12015369},
+     {19695761, 16087646, 28032085, 12999827, 6817792, 11427614, 20244189, -1312777, -13259127, -3402461}},
+    {{30860103, 12735208, -1888245, -4699734, -16974906, 2256940, -8166013, 12298312, -8550524, -10393462},
+     {-5719826, -11245325, -1910649, 15569035, 26642876, -7587760, -5789354, -15118654, -4976164, 12651793},
+     {-2848395, 9953421, 11531313, -5282879, 26895123, -12697089, -13118820, -16517902, 9768698, -2533218}},
+    {{-24719459, 1894651, -287698, -4704085, 15348719, -8156530, 32767513, 12765450, 4940095, 10678226},
+     {18860224, 15980149, -18987240, -1562570, -26233012, -11071856, -7843882, 13944024, -24372348, 16582019},
+     {-15504260, 4970268, -29893044, 4175593, -20993212, -2199756, -11704054, 15444560, -11003761, 7989037}},
+    {{31490452, 5568061, -2412803, 2182383, -32336847, 4531686, -32078269, 6200206, -19686113, -14800171},
+     {-17308668, -15879940, -31522777, -2831, -32887382, 16375549, 8680158, -16371713, 28550068, -6857132},
+     {-28126887, -5688091, 16837845, -1820458, -6850681, 12700016, -30039981, 4364038, 1155602, 5988841}},
+    {{21890435, -13272907, -12624011, 12154349, -7831873, 15300496, 23148983, -4470481, 24618407, 8283181},
+     {-33136107, -10512751, 9975416, 6841041, -31559793, 16356536, 3070187, -7025928, 1466169, 10740210},
+     {-1509399, -15488185, -13503385, -10655916, 32799044, 909394, -13938903, -5779719, -32164649, -15327040}},
+    {{3960823, -14267803, -28026090, -15918051, -19404858, 13146868, 15567327, 951507, -3260321, -573935},
+     {24740841, 5052253, -30094131, 8961361, 25877428, 6165135, -24368180, 14397372, -7380369, -6144105},
+     {-28888365, 3510803, -28103278, -1158478, -11238128, -10631454, -15441463, -14453128, -1625486, -6494814}}
+  }, {
+    {{793299, -9230478, 8836302, -6235707, -27360908, -2369593, 33152843, -4885251, -9906200, -621852},
+     {5666233, 525582, 20782575, -8038419, -24538499, 14657740, 16099374, 1468826, -6171428, -15186581},
+     {-4859255, -3779343, -2917758, -6748019, 7778750, 11688288, -30404353, -9871238, -1558923, -9863646}},
+    {{10896332, -7719704, 824275, 472601, -19460308, 3009587, 25248958, 14783338, -30581476, -15757844},
+     {10566929, 12612572, -31944212, 11118703, -12633376, 12362879, 21752402, 8822496, 24003793, 14264025},
+     {27713862, -7355973, -11008240, 9227530, 27050101, 2504721, 23886875, -13117525, 13958495, -5732453}},
+    {{-23481610, 4867226, -27247128, 3900521, 29838369, -8212291, -31889399, -10041781, 7340521, -15410068},
+     {4646514, -8011124, -22766023, -11532654, 23184553, 8566613, 31366726, -1381061, -15066784, -10375192},
+     {-17270517, 12723032, -16993061, 14878794, 21619651, -6197576, 27584817, 3093888, -8843694, 3849921}},
+    {{-9064912, 2103172, 25561640, -15125738, -5239824, 9582958, 32477045, -9017955, 5002294, -15550259},
+     {-12057553, -11177906, 21115585, -13365155, 8808712, -12030708, 16489530, 13378448, -25845716, 12741426},
+     {-5946367, 10645103, -30911586, 15390284, -3286982, -7118677, 24306472, 15852464, 28834118, -7646072}},
+    {{-17335748, -9107057, -24531279, 9434953, -8472084, -583362, -13090771, 455841, 20461858, 5491305},
+     {13669248, -16095482, -12481974, -10203039, -14569770, -11893198, -24995986, 11293807, -28588204, -9421832},
+     {28497928, 6272777, -33022994, 14470570, 8906179, -1225630, 18504674, -14165166, 29867745, -8795943}},
+    {{-16207023, 13517196, -27799630, -13697798, 24009064, -6373891, -6367600, -13175392, 22853429, -4012011},
+     {24191378, 16712145, -13931797, 15217831, 14542237, 1646131, 18603514, -11037887, 12876623, -2112447},
+     {17902668, 4518229, -411702, -2829247, 26878217, 5258055, -12860753, 608397, 16031844, 3723494}},
+    {{-28632773, 12763728, -20446446, 7577504, 33001348, -13017745, 17558842, -7872890, 23896954, -4314245},
+     {-20005381, -12011952, 31520464, 605201, 2543521, 5991821, -2945064, 7229064, -9919646, -8826859},
+     {28816045, 298879, -28165016, -15920938, 19000928, -1665890, -12680833, -2949325, -18051778, -2082915}},
+    {{16000882, -344896, 3493092, -11447198, -29504595, -13159789, 12577740, 16041268, -19715240, 7847707},
+     {10151868, 10572098, 27312476, 7922682, 14825339, 4723128, -32855931, -6519018, -10020567, 3852848},
+     {-11430470, 15697596, -21121557, -4420647, 5386314, 15063598, 16514493, -15932110, 29330899, -15076224}}
+  }, {
+    {{-25499735, -4378794, -15222908, -6901211, 16615731, 2051784, 3303702, 15490, -27548796, 12314391},
+     {15683520, -6003043, 18109120, -9980648, 15337968, -5997823, -16717435, 15921866, 16103996, -3731215},
+     {-23169824, -10781249, 13588192, -1628807, -3798557, -1074929, -19273607, 5402699, -29815713, -9841101}},
+    {{23190676, 2384583, -32714340, 3462154, -29903655, -1529132, -11266856, 8911517, -25205859, 2739713},
+     {21374101, -3554250, -33524649, 9874411, 15377179, 11831242, -33529904, 6134907, 4931255, 11987849},
+     {-7732, -2978858, -16223486, 7277597, 105524, -322051, -31480539, 13861388, -30076310, 10117930}},
+    {{-29501170, -10744872, -26163768, 13051539, -25625564, 5089643, -6325503, 6704079, 12890019, 15728940},
+     {-21972360, -11771379, -951059, -4418840, 14704840, 2695116, 903376, -10428139, 12885167, 8311031},
+     {-17516482, 5352194, 10384213, -13811658, 7506451, 13453191, 26423267, 4384730, 1888765, -5435404}},
+    {{-25817338, -3107312, -13494599, -3182506, 30896459, -13921729, -32251644, -12707869, -19464434, -3340243},
+     {-23607977, -2665774, -526091, 4651136, 5765089, 4618330, 6092245, 14845197, 17151279, -9854116},
+     {-24830458, -12733720, -15165978, 10367250, -29530908, -265356, 22825805, -7087279, -16866484, 16176525}},
+    {{-23583256, 6564961, 20063689, 3798228, -4740178, 7359225, 2006182, -10363426, -28746253, -10197509},
+     {-10626600, -4486402, -13320562, -5125317, 3432136, -6393229, 23632037, -1940610, 32808310, 1099883},
+     {15030977, 5768825, -27451236, -2887299, -6427378, -15361371, -15277896, -6809350, 2051441, -15225865}},
+    {{-3362323, -7239372, 7517890, 9824992, 23555850, 295369, 5148398, -14154188, -22686354, 16633660},
+     {4577086, -16752288, 13249841, -15304328, 19958763, -14537274, 18559670, -10759549, 8402478, -9864273},
+     {-28406330, -1051581, -26790155, -907698, -17212414, -11030789, 9453451, -14980072, 17983010, 9967138}},
+    {{-25762494, 6524722, 26585488, 9969270, 24709298, 1220360, -1677990, 7806337, 17507396, 3651560},
+     {-10420457, -4118111, 14584639, 15971087, -15768321, 8861010, 26556809, -5574557, -18553322, -11357135},
+     {2839101, 14284142, 4029895, 3472686, 14402957, 12689363, -26642121, 8459447, -5605463, -7621941}},
+    {{-4839289, -3535444, 9744961, 2871048, 25113978, 3187018, -25110813, -849066, 17258084, -7977739},
+     {18164541, -10595176, -17154882, -1542417, 19237078, -9745295, 23357533, -15217008, 26908270, 12150756},
+     {-30264870, -7647865, 5112249, -7036672, -1499807, -6974257, 43168, -5537701, -32302074, 16215819}}
+  }, {
+    {{-6898905, 9824394, -12304779, -4401089, -31397141, -6276835, 32574489, 12532905, -7503072, -8675347},
+     {-27343522, -16515468, -27151524, -10722951, 946346, 16291093, 254968, 7168080, 21676107, -1943028},
+     {21260961, -8424752, -16831886, -11920822, -23677961, 3968121, -3651949, -6215466, -3556191, -7913075}},
+    {{16544754, 13250366, -16804428, 15546242, -4583003, 12757258, -2462308, -8680336, -18907032, -9662799},
+     {-2415239, -15577728, 18312303, 4964443, -15272530, -12653564, 26820651, 16690659, 25459437, -4564609},
+     {-25144690, 11425020, 28423002, -11020557, -6144921, -15826224, 9142795, -2391602, -6432418, -1644817}},
+    {{-23104652, 6253476, 16964147, -3768872, -25113972, -12296437, -27457225, -16344658, 6335692, 7249989},
+     {-30333227, 13979675, 7503222, -12368314, -11956721, -4621693, -30272269, 2682242, 25993170, -12478523},
+     {4364628, 5930691, 32304656, -10044554, -8054781, 15091131, 22857016, -10598955, 31820368, 15075278}},
+    {{31879134, -8918693, 17258761, 90626, -8041836, -4917709, 24162788, -9650886, -17970238, 12833045},
+     {19073683, 14851414, -24403169, -11860168, 7625278, 11091125, -19619190, 2074449, -9413939, 14905377},
+     {24483667, -11935567, -2518866, -11547418, -1553130, 15355506, -25282080, 9253129, 27628530, -7555480}},
+    {{17597607, 8340603, 19355617, 552187, 26198470, -3176583, 4593324, -9157582, -14110875, 15297016},
+     {510886, 14337390, -31785257, 16638632, 6328095, 2713355, -20217417, -11864220, 8683221, 2921426},
+     {18606791, 11874196, 27155355, -5281482, -24031742, 6265446, -25178240, -1278924, 4674690, 13890525}},
+    {{13609624, 13069022, -27372361, -13055908, 24360586, 9592974, 14977157, 9835105, 4389687, 288396},
+     {9922506, -519394, 13613107, 5883594, -18758345, -434263, -12304062, 8317628, 23388070, 16052080},
+     {12720016, 11937594, -31970060, -5028689, 26900120, 8561328, -20155687, -11632979, -14754271, -10812892}},
+    {{15961858, 14150409, 26716931, -665832, -22794328, 13603569, 11829573, 7467844, -28822128, 929275},
+     {11038231, -11582396, -27310482, -7316562, -10498527, -16307831, -23479533, -9371869, -21393143, 2465074},
+     {20017163, -4323226, 27915242, 1529148, 12396362, 15675764, 13817261, -9658066, 2463391, -4622140}},
+    {{-16358878, -12663911, -12065183, 4996454, -1256422, 1073572, 9583558, 12851107, 4003896, 12673717},
+     {-1731589, -15155870, -3262930, 16143082, 19294135, 13385325, 14741514, -9103726, 7903886, 2348101},
+     {24536016, -16515207, 12715592, -3862155, 1511293, 10047386, -3842346, -7129159, -28377538, 10048127}}
+  }, {
+    {{-12622226, -6204820, 30718825, 2591312, -10617028, 12192840, 18873298, -7297090, -32297756, 15221632},
+     {-26478122, -11103864, 11546244, -1852483, 9180880, 7656409, -21343950, 2095755, 29769758, 6593415},
+     {-31994208, -2907461, 4176912, 3264766, 12538965, -868111, 26312345, -6118678, 30958054, 8292160}},
+    {{31429822, -13959116, 29173532, 15632448, 12174511, -2760094, 32808831, 3977186, 26143136, -3148876},
+     {22648901, 1402143, -22799984, 13746059, 7936347, 365344, -8668633, -1674433, -3758243, -2304625},
+     {-15491917, 8012313, -2514730, -12702462, -23965846, -10254029, -1612713, -1535569, -16664475, 8194478}},
+    {{27338066, -7507420, -7414224, 10140405, -19026427, -6589889, 27277191, 8855376, 28572286, 3005164},
+     {26287124, 4821776, 25476601, -4145903, -3764513, -15788984, -18008582, 1182479, -26094821, -13079595},
+     {-7171154, 3178080, 23970071, 6201893, -17195577, -4489192, -21876275, -13982627, 32208683, -1198248}},
+    {{-16657702, 2817643, -10286362, 14811298, 6024667, 13349505, -27315504, -10497842, -27672585, -11539858},
+     {15941029, -9405932, -21367050, 8062055, 31876073, -238629, -15278393, -1444429, 15397331, -4130193},
+     {8934485, -13485467, -23286397, -13423241, -32446090, 14047986, 31170398, -1441021, -27505566, 15087184}},
+    {{-18357243, -2156491, 24524913, -16677868, 15520427, -6360776, -15502406, 11461896, 16788528, -5868942},
+     {-1947386, 16013773, 21750665, 3714552, -17401782, -16055433, -3770287, -10323320, 31322514, -11615635},
+     {21426655, -5650218, -13648287, -5347537, -28812189, -4920970, -18275391, -14621414, 13040862, -12112948}},
+    {{11293895, 12478086, -27136401, 15083750, -29307421, 14748872, 14555558, -13417103, 1613711, 4896935},
+     {-25894883, 15323294, -8489791, -8057900, 25967126, -13425460, 2825960, -4897045, -23971776, -11267415},
+     {-15924766, -5229880, -17443532, 6410664, 3622847, 10243618, 20615400, 12405433, -23753030, -8436416}},
+    {{-7091295, 12556208, -20191352, 9025187, -17072479, 4333801, 4378436, 2432030, 23097949, -566018},
+     {4565804, -16025654, 20084412, -7842817, 1724999, 189254, 24767264, 10103221, -18512313, 2424778},
+     {366633, -11976806, 8173090, -6890119, 30788634, 5745705, -7168678, 1344109, -3642553, 12412659}},
+    {{-24001791, 7690286, 14929416, -168257, -32210835, -13412986, 24162697, -15326504, -3141501, 11179385},
+     {18289522, -14724954, 8056945, 16430056, -21729724, 7842514, -6001441, -1486897, -18684645, -11443503},
+     {476239, 6601091, -6152790, -9723375, 17503545, -4863900, 27672959, 13403813, 11052904, 5219329}}
+  }, {
+    {{20678546, -8375738, -32671898, 8849123, -5009758, 14574752, 31186971, -3973730, 9014762, -8579056},
+     {-13644050, -10350239, -15962508, 5075808, -1514661, -11534600, -33102500, 9160280, 8473550, -3256838},
+     {24900749, 14435722, 17209120, -15292541, -22592275, 9878983, -7689309, -16335821, -24568481, 11788948}},
+    {{-3118155, -11395194, -13802089, 14797441, 9652448, -6845904, -20037437, 10410733, -24568470, -1458691},
+     {-15659161, 16736706, -22467150, 10215878, -9097177, 7563911, 11871841, -12505194, -18513325, 8464118},
+     {-23400612, 8348507, -14585951, -861714, -3950205, -6373419, 14325289, 8628612, 33313881, -8370517}},
+    {{-20186973, -4967935, 22367356, 5271547, -1097117, -4788838, -24805667, -10236854, -8940735, -5818269},
+     {-6948785, -1795212, -32625683, -16021179, 32635414, -7374245, 15989197, -12838188, 28358192, -4253904},
+     {-23561781, -2799059, -32351682, -1661963, -9147719, 10429267, -16637684, 4072016, -5351664, 5596589}},
+    {{-28236598, -3390048, 12312896, 6213178, 3117142, 16078565, 29266239, 2557221, 1768301, 15373193},
+     {-7243358, -3246960, -4593467, -7553353, -127927, -912245, -1090902, -4504991, -24660491, 3442910},
+     {-30210571, 5124043, 14181784, 8197961, 18964734, -11939093, 22597931, 7176455, -18585478, 13365930}},
+    {{-7877390, -1499958, 8324673, 4690079, 6261860, 890446, 24538107, -8570186, -9689599, -3031667},
+     {25008904, -10771599, -4305031, -9638010, 16265036, 15721635, 683793, -11823784, 15723479, -15163481},
+     {-9660625, 12374379, -27006999, -7026148, -7724114, -12314514, 11879682, 5400171, 519526, -1235876}},
+    {{22258397, -16332233, -7869817, 14613016, -22520255, -2950923, -20353881, 7315967, 16648397, 7605640},
+     {-8081308, -8464597, -8223311, 9719710, 19259459, -15348212, 23994942, -5281555, -9468848, 4763278},
+     {-21699244, 9220969, -15730624, 1084137, -25476107, -2852390, 31088447, -7764523, -11356529, 728112}},
+    {{26047220, -11751471, -6900323, -16521798, 24092068, 9158119, -4273545, -12555558, -29365436, -5498272},
+     {17510331, -322857, 5854289, 8403524, 17133918, -3112612, -28111007, 12327945, 10750447, 10014012},
+     {-10312768, 3936952, 9156313, -8897683, 16498692, -994647, -27481051, -666732, 3424691, 7540221}},
+    {{30322361, -6964110, 11361005, -4143317, 7433304, 4989748, -7071422, -16317219, -9244265, 15258046},
+     {13054562, -2779497, 19155474, 469045, -12482797, 4566042, 5631406, 2711395, 1062915, -5136345},
+     {-19240248, -11254599, -29509029, -7499965, -5835763, 13005411, -6066489, 12194497, 32960380, 1459310}}
+  }, {
+    {{19852034, 7027924, 23669353, 10020366, 8586503, -6657907, 394197, -6101885, 18638003, -11174937},
+     {31395534, 15098109, 26581030, 8030562, -16527914, -5007134, 9012486, -7584354, -6643087, -5442636},
+     {-9192165, -2347377, -1997099, 4529534, 25766844, 607986, -13222, 9677543, -32294889, -6456008}},
+    {{-2444496, -149937, 29348902, 8186665, 1873760, 12489863, -30934579, -7839692, -7852844, -8138429},
+     {-15236356, -15433509, 7766470, 746860, 26346930, -10221762, -27333451, 10754588, -9431476, 5203576},
+     {31834314, 14135496, -770007, 5159118, 20917671, -16768096, -7467973, -7337524, 31809243, 7347066}},
+    {{-9606723, -11874240, 20414459, 13033986, 13716524, -11691881, 19797970, -12211255, 15192876, -2087490},
+     {-12663563, -2181719, 1168162, -3804809, 26747877, -14138091, 10609330, 12694420, 33473243, -13382104},
+     {33184999, 11180355, 15832085, -11385430, -1633671, 225884, 15089336, -11023903, -6135662, 14480053}},
+    {{31308717, -5619998, 31030840, -1897099, 15674547, -6582883, 5496208, 13685227, 27595050, 8737275},
+     {-20318852, -15150239, 10933843, -16178022, 8335352, -7546022, -31008351, -12610604, 26498114, 66511},
+     {22644454, -8761729, -16671776, 4884562, -3105614, -13559366, 30540766, -4286747, -13327787, -7515095}},
+    {{-28017847, 9834845, 18617207, -2681312, -3401956, -13307506, 8205540, 13585437, -17127465, 15115439},
+     {23711543, -672915, 31206561, -8362711, 6164647, -9709987, -33535882, -1426096, 8236921, 16492939},
+     {-23910559, -13515526, -26299483, -4503841, 25005590, -7687270, 19574902, 10071562, 6708380, -6222424}},
+    {{2101391, -4930054, 19702731, 2367575, -15427167, 1047675, 5301017, 9328700, 29955601, -11678310},
+     {3096359, 9271816, -21620864, -15521844, -14847996, -7592937, -25892142, -12635595, -9917575, 6216608},
+     {-32615849, 338663, -25195611, 2510422, -29213566, -13820213, 24822830, -6146567, -26767480, 7525079}},
+    {{-23066649, -13985623, 16133487, -7896178, -3389565, 778788, -910336, -2782495, -19386633, 11994101},
+     {21691500, -13624626, -641331, -14367021, 3285881, -3483596, -25064666, 9718258, -7477437, 13381418},
+     {18445390, -4202236, 14979846, 11622458, -1727110, -3582980, 23111648, -6375247, 28535282, 15779576}},
+    {{30098053, 3089662, -9234387, 16662135, -21306940, 11308411, -14068454, 12021730, 9955285, -16303356},
+     {9734894, -14576830, -7473633, -9138735, 2060392, 11313496, -18426029, 9924399, 20194861, 13380996},
+     {-26378102, -7965207, -22167821, 15789297, -18055342, -6168792, -1984914, 15707771, 26342023, 10146099}}
+  }, {
+    {{-26016874, -219943, 21339191, -41388, 19745256, -2878700, -29637280, 2227040, 21612326, -545728},
+     {-13077387, 1184228, 23562814, -5970442, -20351244, -6348714, 25764461, 12243797, -20856566, 11649658},
+     {-10031494, 11262626, 27384172, 2271902, 26947504, -15997771, 39944, 6114064, 33514190, 2333242}},
+    {{-21433588, -12421821, 8119782, 7219913, -21830522, -9016134, -6679750, -12670638, 24350578, -13450001},
+     {-4116307, -11271533, -23886186, 4843615, -30088339, 690623, -31536088, -10406836, 8317860, 12352766},
+     {18200138, -14475911, -33087759, -2696619, -23702521, -9102511, -23552096, -2287550, 20712163, 6719373}},
+    {{26656208, 6075253, -7858556, 1886072, -28344043, 4262326, 11117530, -3763210, 26224235, -3297458},
+     {-17168938, -14854097, -3395676, -16369877, -19954045, 14050420, 21728352, 9493610, 18620611, -16428628},
+     {-13323321, 13325349, 11432106, 5964811, 18609221, 6062965, -5269471, -9725556, -30701573, -16479657}},
+    {{-23860538, -11233159, 26961357, 1640861, -32413112, -16737940, 12248509, -5240639, 13735342, 1934062},
+     {25089769, 6742589, 17081145, -13406266, 21909293, -16067981, -15136294, -3765346, -21277997, 5473616},
+     {31883677, -7961101, 1083432, -11572403, 22828471, 13290673, -7125085, 12469656, 29111212, -5451014}},
+    {{24244947, -15050407, -26262976, 2791540, -14997599, 16666678, 24367466, 6388839, -10295587, 452383},
+     {-25640782, -3417841, 5217916, 16224624, 19987036, -4082269, -24236251, -5915248, 15766062, 8407814},
+     {-20406999, 13990231, 15495425, 16395525, 5377168, 15166495, -8917023, -4388953, -8067909, 2276718}},
+    {{30157918, 12924066, -17712050, 9245753, 19895028, 3368142, -23827587, 5096219, 22740376, -7303417},
+     {2041139, -14256350, 7783687, 13876377, -25946985, -13352459, 24051124, 13742383, -15637599, 13295222},
+     {33338237, -8505733, 12532113, 7977527, 9106186, -1715251, -17720195, -4612972, -4451357, -14669444}},
+    {{-20045281, 5454097, -14346548, 6447146, 28862071, 1883651, -2469266, -4141880, 7770569, 9620597},
+     {23208068, 7979712, 33071466, 8149229, 1758231, -10834995, 30945528, -1694323, -33502340, -14767970},
+     {1439958, -16270480, -1079989, -793782, 4625402, 10647766, -5043801, 1220118, 30494170, -11440799}},
+    {{-5037580, -13028295, -2970559, -3061767, 15640974, -6701666, -26739026, 926050, -1684339, -13333647},
+     {13908495, -3549272, 30919928, -6273825, -21521863, 7989039, 9021034, 9078865, 3353509, 4033511},
+     {-29663431, -15113610, 32259991, -344482, 24295849, -12912123, 23161163, 8839127, 27485041, 7356032}}
+  }, {
+    {{9661027, 705443, 11980065, -5370154, -1628543, 14661173, -6346142, 2625015, 28431036, -16771834},
+     {-23839233, -8311415, -25945511, 7480958, -17681669, -8354183, -22545972, 14150565, 15970762, 4099461},
+     {29262576, 16756590, 26350592, -8793563, 8529671, -11208050, 13617293, -9937143, 11465739, 8317062}},
+    {{-25493081, -6962928, 32500200, -9419051, -23038724, -2302222, 14898637, 3848455, 20969334, -5157516},
+     {-20384450, -14347713, -18336405, 13884722, -33039454, 2842114, -21610826, -3649888, 11177095, 14989547},
+     {-24496721, -11716016, 16959896, 2278463, 12066309, 10137771, 13515641, 2581286, -28487508, 9930240}},
+    {{-17751622, -2097826, 16544300, -13009300, -15914807, -14949081, 18345767, -13403753, 16291481, -5314038},
+     {-33229194, 2553288, 32678213, 9875984, 8534129, 6889387, -9676774, 6957617, 4368891, 9788741},
+     {16660756, 7281060, -10830758, 12911820, 20108584, -8101676, -21722536, -8613148, 16250552, -11111103}},
+    {{-19765507, 2390526, -16551031, 14161980, 1905286, 6414907, 4689584, 10604807, -30190403, 4782747},
+     {-1354539, 14736941, -7367442, -13292886, 7710542, -14155590, -9981571, 4383045, 22546403, 437323},
+     {31665577, -12180464, -16186830, 1491339, -18368625, 3294682, 27343084, 2786261, -30633590, -14097016}},
+    {{-14467279, -683715, -33374107, 7448552, 19294360, 14334329, -19690631, 2355319, -19284671, -6114373},
+     {15121312, -15796162, 6377020, -6031361, -10798111, -12957845, 18952177, 15496498, -29380133, 11754228},
+     {-2637277, -13483075, 8488727, -14303896, 12728761, -1622493, 7141596, 11724556, 22761615, -10134141}},
+    {{16918416, 11729663, -18083579, 3022987, -31015732, -13339659, -28741185, -12227393, 32851222, 11717399},
+     {11166634, 7338049, -6722523, 4531520, -29468672, -7302055, 31474879, 3483633, -1193175, -4030831},
+     {-185635, 9921305, 31456609, -13536438, -12013818, 13348923, 33142652, 6546660, -19985279, -3948376}},
+    {{-32460596, 11266712, -11197107, -7899103, 31703694, 3855903, -8537131, -12833048, -30772034, -15486313},
+     {-18006477, 12709068, 3991746, -6479188, -21491523, -10550425, -31135347, -16049879, 10928917, 3011958},
+     {-6957757, -15594337, 31696059, 334240, 29576716, 14796075, -30831056, -12805180, 18008031, 10258577}},
+    {{-22448644, 15655569, 7018479, -4410003, -30314266, -1201591, -1853465, 1367120, 25127874, 6671743},
+     {29701166, -14373934, -10878120, 9279288, -17568, 13127210, 21382910, 11042292, 25838796, 4642684},
+     {-20430234, 14955537, -24126347, 8124619, -5369288, -5990470, 30468147, -13900640, 18423289, 4177476}}
+  }
+};
+
+const ge_precomp ge_Bi[8] = {
+  {{25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605},
+   {-12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378},
+   {-8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546}}, {{15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024},
+   {16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574},
+   {30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357}}, {{10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380},
+   {4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306},
+   {19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942}}, {{5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766},
+   {-30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701},
+   {28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300}}, {{-22518993, -6692182, 14201702, -8745502, -23510406, 8844726, 18474211, -1361450, -13062696, 13821877},
+   {-6455177, -7839871, 3374702, -4740862, -27098617, -10571707, 31655028, -7212327, 18853322, -14220951},
+   {4566830, -12963868, -28974889, -12240689, -7602672, -2830569, -8514358, -10431137, 2207753, -3209784}}, {{-25154831, -4185821, 29681144, 7868801, -6854661, -9423865, -12437364, -663000, -31111463, -16132436},
+   {25576264, -2703214, 7349804, -11814844, 16472782, 9300885, 3844789, 15725684, 171356, 6466918},
+   {23103977, 13316479, 9739013, -16149481, 817875, -15038942, 8965339, -14088058, -30714912, 16193877}}, {{-33521811, 3180713, -2394130, 14003687, -16903474, -16270840, 17238398, 4729455, -18074513, 9256800},
+   {-25182317, -4174131, 32336398, 5036987, -21236817, 11360617, 22616405, 9761698, -19827198, 630305},
+   {-13720693, 2639453, -24237460, -7406481, 9494427, -5774029, -6554551, -15960994, -2449256, -14291300}}, {{-3151181, -5046075, 9282714, 6866145, -31907062, -863023, -18940575, 15033784, 25105118, -7894876},
+   {-24326370, 15950226, -31801215, -14592823, -11662737, -5090925, 1573892, -2625887, 2198790, -15804619},
+   {-3099351, 10324967, -2241613, 7453183, -5446979, -2735503, -13812022, -16236442, -32461234, -12290683}}
+};
+
+/* A = 2 * (1 - d) / (1 + d) = 486662 */
+const fe fe_ma2 = {-12721188, -3529, 0, 0, 0, 0, 0, 0, 0, 0}; /* -A^2 */
+const fe fe_ma = {-486662, 0, 0, 0, 0, 0, 0, 0, 0, 0}; /* -A */
+const fe fe_fffb1 = {-31702527, -2466483, -26106795, -12203692, -12169197, -321052, 14850977, -10296299, -16929438, -407568}; /* sqrt(-2 * A * (A + 2)) */
+const fe fe_fffb2 = {8166131, -6741800, -17040804, 3154616, 21461005, 1466302, -30876704, -6368709, 10503587, -13363080}; /* sqrt(2 * A * (A + 2)) */
+const fe fe_fffb3 = {-13620103, 14639558, 4532995, 7679154, 16815101, -15883539, -22863840, -14813421, 13716513, -6477756}; /* sqrt(-sqrt(-1) * A * (A + 2)) */
+const fe fe_fffb4 = {-21786234, -12173074, 21573800, 4524538, -4645904, 16204591, 8012863, -8444712, 3212926, 6885324}; /* sqrt(sqrt(-1) * A * (A + 2)) */
diff --git a/crypt/monero_crypto/crypto_ops_builder/crypto-ops-old.c b/crypt/monero_crypto/crypto_ops_builder/crypto-ops-old.c
new file mode 100644
index 0000000000..b7a290b4ae
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/crypto-ops-old.c
@@ -0,0 +1,3008 @@
+// 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
+
+
+#include <stdint.h> //standard
+#include <assert.h> //standard
+
+//#include "warnings.h" //where is this??
+#include "crypto-ops.h" //fine
+
+//DISABLE_VS_WARNINGS(4146 4244)
+
+/* Predeclarations */
+
+static void fe_mul(fe, const fe, const fe);
+static void fe_sq(fe, const fe);
+static void fe_tobytes(unsigned char *, const fe);
+static void ge_madd(ge_p1p1 *, const ge_p3 *, const ge_precomp *);
+static void ge_msub(ge_p1p1 *, const ge_p3 *, const ge_precomp *);
+static void ge_p2_0(ge_p2 *);
+static void ge_p3_dbl(ge_p1p1 *, const ge_p3 *);
+static void ge_sub(ge_p1p1 *, const ge_p3 *, const ge_cached *);
+static void fe_divpowm1(fe, const fe, const fe);
+
+/* Common functions */
+
+//x 
+//u
+static uint64_t load_3(const unsigned char *in) {
+  uint64_t result;
+  result = (uint64_t) in[0];
+  result |= ((uint64_t) in[1]) << 8;
+  result |= ((uint64_t) in[2]) << 16;
+  return result;
+}
+
+//x 
+//u
+static uint64_t load_4(const unsigned char *in)
+{
+  uint64_t result;
+  result = (uint64_t) in[0];
+  result |= ((uint64_t) in[1]) << 8;
+  result |= ((uint64_t) in[2]) << 16;
+  result |= ((uint64_t) in[3]) << 24;
+  return result;
+}
+
+/* From fe_0.c */
+
+/*
+h = 0
+*/
+
+//x
+static void fe_0(fe h) {
+  h[0] = 0;
+  h[1] = 0;
+  h[2] = 0;
+  h[3] = 0;
+  h[4] = 0;
+  h[5] = 0;
+  h[6] = 0;
+  h[7] = 0;
+  h[8] = 0;
+  h[9] = 0;
+}
+
+/* From fe_1.c */
+
+/*
+h = 1
+*/
+
+//x
+static void fe_1(fe h) {
+  h[0] = 1;
+  h[1] = 0;
+  h[2] = 0;
+  h[3] = 0;
+  h[4] = 0;
+  h[5] = 0;
+  h[6] = 0;
+  h[7] = 0;
+  h[8] = 0;
+  h[9] = 0;
+}
+
+/* From fe_add.c */
+
+/*
+h = f + g
+Can overlap h with f or g.
+
+Preconditions:
+   |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+   |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+
+Postconditions:
+   |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+static void fe_add(fe h, const fe f, const fe g) {
+  int32_t f0 = f[0];
+  int32_t f1 = f[1];
+  int32_t f2 = f[2];
+  int32_t f3 = f[3];
+  int32_t f4 = f[4];
+  int32_t f5 = f[5];
+  int32_t f6 = f[6];
+  int32_t f7 = f[7];
+  int32_t f8 = f[8];
+  int32_t f9 = f[9];
+  int32_t g0 = g[0];
+  int32_t g1 = g[1];
+  int32_t g2 = g[2];
+  int32_t g3 = g[3];
+  int32_t g4 = g[4];
+  int32_t g5 = g[5];
+  int32_t g6 = g[6];
+  int32_t g7 = g[7];
+  int32_t g8 = g[8];
+  int32_t g9 = g[9];
+  int32_t h0 = f0 + g0;
+  int32_t h1 = f1 + g1;
+  int32_t h2 = f2 + g2;
+  int32_t h3 = f3 + g3;
+  int32_t h4 = f4 + g4;
+  int32_t h5 = f5 + g5;
+  int32_t h6 = f6 + g6;
+  int32_t h7 = f7 + g7;
+  int32_t h8 = f8 + g8;
+  int32_t h9 = f9 + g9;
+  h[0] = h0;
+  h[1] = h1;
+  h[2] = h2;
+  h[3] = h3;
+  h[4] = h4;
+  h[5] = h5;
+  h[6] = h6;
+  h[7] = h7;
+  h[8] = h8;
+  h[9] = h9;
+}
+
+/* From fe_cmov.c */
+
+/*
+Replace (f,g) with (g,g) if b == 1;
+replace (f,g) with (f,g) if b == 0.
+
+Preconditions: b in {0,1}.
+*/
+
+//x
+static void fe_cmov(fe f, const fe g, unsigned int b) {
+  int32_t f0 = f[0];
+  int32_t f1 = f[1];
+  int32_t f2 = f[2];
+  int32_t f3 = f[3];
+  int32_t f4 = f[4];
+  int32_t f5 = f[5];
+  int32_t f6 = f[6];
+  int32_t f7 = f[7];
+  int32_t f8 = f[8];
+  int32_t f9 = f[9];
+  int32_t g0 = g[0];
+  int32_t g1 = g[1];
+  int32_t g2 = g[2];
+  int32_t g3 = g[3];
+  int32_t g4 = g[4];
+  int32_t g5 = g[5];
+  int32_t g6 = g[6];
+  int32_t g7 = g[7];
+  int32_t g8 = g[8];
+  int32_t g9 = g[9];
+  int32_t x0 = f0 ^ g0;
+  int32_t x1 = f1 ^ g1;
+  int32_t x2 = f2 ^ g2;
+  int32_t x3 = f3 ^ g3;
+  int32_t x4 = f4 ^ g4;
+  int32_t x5 = f5 ^ g5;
+  int32_t x6 = f6 ^ g6;
+  int32_t x7 = f7 ^ g7;
+  int32_t x8 = f8 ^ g8;
+  int32_t x9 = f9 ^ g9;
+  assert((((b - 1) & ~b) | ((b - 2) & ~(b - 1))) == (unsigned int) -1);
+  b = -b;
+  x0 &= b;
+  x1 &= b;
+  x2 &= b;
+  x3 &= b;
+  x4 &= b;
+  x5 &= b;
+  x6 &= b;
+  x7 &= b;
+  x8 &= b;
+  x9 &= b;
+  f[0] = f0 ^ x0;
+  f[1] = f1 ^ x1;
+  f[2] = f2 ^ x2;
+  f[3] = f3 ^ x3;
+  f[4] = f4 ^ x4;
+  f[5] = f5 ^ x5;
+  f[6] = f6 ^ x6;
+  f[7] = f7 ^ x7;
+  f[8] = f8 ^ x8;
+  f[9] = f9 ^ x9;
+}
+
+/* From fe_copy.c */
+
+/*
+h = f
+*/
+
+//x
+static void fe_copy(fe h, const fe f) {
+  int32_t f0 = f[0];
+  int32_t f1 = f[1];
+  int32_t f2 = f[2];
+  int32_t f3 = f[3];
+  int32_t f4 = f[4];
+  int32_t f5 = f[5];
+  int32_t f6 = f[6];
+  int32_t f7 = f[7];
+  int32_t f8 = f[8];
+  int32_t f9 = f[9];
+  h[0] = f0;
+  h[1] = f1;
+  h[2] = f2;
+  h[3] = f3;
+  h[4] = f4;
+  h[5] = f5;
+  h[6] = f6;
+  h[7] = f7;
+  h[8] = f8;
+  h[9] = f9;
+}
+
+/* From fe_invert.c */
+
+//x using fermat
+static void fe_invert(fe out, const fe z) {
+  fe t0;
+  fe t1;
+  fe t2;
+  fe t3;
+  int i;
+
+  fe_sq(t0, z);
+  fe_sq(t1, t0);
+  fe_sq(t1, t1);
+  fe_mul(t1, z, t1);
+  fe_mul(t0, t0, t1);
+  fe_sq(t2, t0);
+  fe_mul(t1, t1, t2);
+  fe_sq(t2, t1);
+  for (i = 0; i < 4; ++i) {
+    fe_sq(t2, t2);
+  }
+  fe_mul(t1, t2, t1);
+  fe_sq(t2, t1);
+  for (i = 0; i < 9; ++i) {
+    fe_sq(t2, t2);
+  }
+  fe_mul(t2, t2, t1);
+  fe_sq(t3, t2);
+  for (i = 0; i < 19; ++i) {
+    fe_sq(t3, t3);
+  }
+  fe_mul(t2, t3, t2);
+  fe_sq(t2, t2);
+  for (i = 0; i < 9; ++i) {
+    fe_sq(t2, t2);
+  }
+  fe_mul(t1, t2, t1);
+  fe_sq(t2, t1);
+  for (i = 0; i < 49; ++i) {
+    fe_sq(t2, t2);
+  }
+  fe_mul(t2, t2, t1);
+  fe_sq(t3, t2);
+  for (i = 0; i < 99; ++i) {
+    fe_sq(t3, t3);
+  }
+  fe_mul(t2, t3, t2);
+  fe_sq(t2, t2);
+  for (i = 0; i < 49; ++i) {
+    fe_sq(t2, t2);
+  }
+  fe_mul(t1, t2, t1);
+  fe_sq(t1, t1);
+  for (i = 0; i < 4; ++i) {
+    fe_sq(t1, t1);
+  }
+  fe_mul(out, t1, t0);
+
+  return;
+}
+
+/* From fe_isnegative.c */
+
+/*
+return 1 if f is in {1,3,5,...,q-2}
+return 0 if f is in {0,2,4,...,q-1}
+
+Preconditions:
+   |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+//x
+static int fe_isnegative(const fe f) {
+  unsigned char s[32];
+  fe_tobytes(s, f);
+  return s[0] & 1;
+}
+
+/* From fe_isnonzero.c, modified */
+
+//x
+static int fe_isnonzero(const fe f) {
+  unsigned char s[32];
+  fe_tobytes(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;
+}
+
+/* From fe_mul.c */
+
+/*
+h = f * g
+Can overlap h with f or g.
+
+Preconditions:
+   |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+   |g| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+
+Postconditions:
+   |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
+*/
+
+/*
+Notes on implementation strategy:
+
+Using schoolbook multiplication.
+Karatsuba would save a little in some cost models.
+
+Most multiplications by 2 and 19 are 32-bit precomputations;
+cheaper than 64-bit postcomputations.
+
+There is one remaining multiplication by 19 in the carry chain;
+one *19 precomputation can be merged into this,
+but the resulting data flow is considerably less clean.
+
+There are 12 carries below.
+10 of them are 2-way parallelizable and vectorizable.
+Can get away with 11 carries, but then data flow is much deeper.
+
+With tighter constraints on inputs can squeeze carries into int32.
+*/
+
+static void fe_mul(fe h, const fe f, const fe g) {
+  int32_t f0 = f[0];
+  int32_t f1 = f[1];
+  int32_t f2 = f[2];
+  int32_t f3 = f[3];
+  int32_t f4 = f[4];
+  int32_t f5 = f[5];
+  int32_t f6 = f[6];
+  int32_t f7 = f[7];
+  int32_t f8 = f[8];
+  int32_t f9 = f[9];
+  int32_t g0 = g[0];
+  int32_t g1 = g[1];
+  int32_t g2 = g[2];
+  int32_t g3 = g[3];
+  int32_t g4 = g[4];
+  int32_t g5 = g[5];
+  int32_t g6 = g[6];
+  int32_t g7 = g[7];
+  int32_t g8 = g[8];
+  int32_t g9 = g[9];
+  int32_t g1_19 = 19 * g1; /* 1.959375*2^29 */
+  int32_t g2_19 = 19 * g2; /* 1.959375*2^30; still ok */
+  int32_t g3_19 = 19 * g3;
+  int32_t g4_19 = 19 * g4;
+  int32_t g5_19 = 19 * g5;
+  int32_t g6_19 = 19 * g6;
+  int32_t g7_19 = 19 * g7;
+  int32_t g8_19 = 19 * g8;
+  int32_t g9_19 = 19 * g9;
+  int32_t f1_2 = 2 * f1;
+  int32_t f3_2 = 2 * f3;
+  int32_t f5_2 = 2 * f5;
+  int32_t f7_2 = 2 * f7;
+  int32_t f9_2 = 2 * f9;
+  int64_t f0g0    = f0   * (int64_t) g0;
+  int64_t f0g1    = f0   * (int64_t) g1;
+  int64_t f0g2    = f0   * (int64_t) g2;
+  int64_t f0g3    = f0   * (int64_t) g3;
+  int64_t f0g4    = f0   * (int64_t) g4;
+  int64_t f0g5    = f0   * (int64_t) g5;
+  int64_t f0g6    = f0   * (int64_t) g6;
+  int64_t f0g7    = f0   * (int64_t) g7;
+  int64_t f0g8    = f0   * (int64_t) g8;
+  int64_t f0g9    = f0   * (int64_t) g9;
+  int64_t f1g0    = f1   * (int64_t) g0;
+  int64_t f1g1_2  = f1_2 * (int64_t) g1;
+  int64_t f1g2    = f1   * (int64_t) g2;
+  int64_t f1g3_2  = f1_2 * (int64_t) g3;
+  int64_t f1g4    = f1   * (int64_t) g4;
+  int64_t f1g5_2  = f1_2 * (int64_t) g5;
+  int64_t f1g6    = f1   * (int64_t) g6;
+  int64_t f1g7_2  = f1_2 * (int64_t) g7;
+  int64_t f1g8    = f1   * (int64_t) g8;
+  int64_t f1g9_38 = f1_2 * (int64_t) g9_19;
+  int64_t f2g0    = f2   * (int64_t) g0;
+  int64_t f2g1    = f2   * (int64_t) g1;
+  int64_t f2g2    = f2   * (int64_t) g2;
+  int64_t f2g3    = f2   * (int64_t) g3;
+  int64_t f2g4    = f2   * (int64_t) g4;
+  int64_t f2g5    = f2   * (int64_t) g5;
+  int64_t f2g6    = f2   * (int64_t) g6;
+  int64_t f2g7    = f2   * (int64_t) g7;
+  int64_t f2g8_19 = f2   * (int64_t) g8_19;
+  int64_t f2g9_19 = f2   * (int64_t) g9_19;
+  int64_t f3g0    = f3   * (int64_t) g0;
+  int64_t f3g1_2  = f3_2 * (int64_t) g1;
+  int64_t f3g2    = f3   * (int64_t) g2;
+  int64_t f3g3_2  = f3_2 * (int64_t) g3;
+  int64_t f3g4    = f3   * (int64_t) g4;
+  int64_t f3g5_2  = f3_2 * (int64_t) g5;
+  int64_t f3g6    = f3   * (int64_t) g6;
+  int64_t f3g7_38 = f3_2 * (int64_t) g7_19;
+  int64_t f3g8_19 = f3   * (int64_t) g8_19;
+  int64_t f3g9_38 = f3_2 * (int64_t) g9_19;
+  int64_t f4g0    = f4   * (int64_t) g0;
+  int64_t f4g1    = f4   * (int64_t) g1;
+  int64_t f4g2    = f4   * (int64_t) g2;
+  int64_t f4g3    = f4   * (int64_t) g3;
+  int64_t f4g4    = f4   * (int64_t) g4;
+  int64_t f4g5    = f4   * (int64_t) g5;
+  int64_t f4g6_19 = f4   * (int64_t) g6_19;
+  int64_t f4g7_19 = f4   * (int64_t) g7_19;
+  int64_t f4g8_19 = f4   * (int64_t) g8_19;
+  int64_t f4g9_19 = f4   * (int64_t) g9_19;
+  int64_t f5g0    = f5   * (int64_t) g0;
+  int64_t f5g1_2  = f5_2 * (int64_t) g1;
+  int64_t f5g2    = f5   * (int64_t) g2;
+  int64_t f5g3_2  = f5_2 * (int64_t) g3;
+  int64_t f5g4    = f5   * (int64_t) g4;
+  int64_t f5g5_38 = f5_2 * (int64_t) g5_19;
+  int64_t f5g6_19 = f5   * (int64_t) g6_19;
+  int64_t f5g7_38 = f5_2 * (int64_t) g7_19;
+  int64_t f5g8_19 = f5   * (int64_t) g8_19;
+  int64_t f5g9_38 = f5_2 * (int64_t) g9_19;
+  int64_t f6g0    = f6   * (int64_t) g0;
+  int64_t f6g1    = f6   * (int64_t) g1;
+  int64_t f6g2    = f6   * (int64_t) g2;
+  int64_t f6g3    = f6   * (int64_t) g3;
+  int64_t f6g4_19 = f6   * (int64_t) g4_19;
+  int64_t f6g5_19 = f6   * (int64_t) g5_19;
+  int64_t f6g6_19 = f6   * (int64_t) g6_19;
+  int64_t f6g7_19 = f6   * (int64_t) g7_19;
+  int64_t f6g8_19 = f6   * (int64_t) g8_19;
+  int64_t f6g9_19 = f6   * (int64_t) g9_19;
+  int64_t f7g0    = f7   * (int64_t) g0;
+  int64_t f7g1_2  = f7_2 * (int64_t) g1;
+  int64_t f7g2    = f7   * (int64_t) g2;
+  int64_t f7g3_38 = f7_2 * (int64_t) g3_19;
+  int64_t f7g4_19 = f7   * (int64_t) g4_19;
+  int64_t f7g5_38 = f7_2 * (int64_t) g5_19;
+  int64_t f7g6_19 = f7   * (int64_t) g6_19;
+  int64_t f7g7_38 = f7_2 * (int64_t) g7_19;
+  int64_t f7g8_19 = f7   * (int64_t) g8_19;
+  int64_t f7g9_38 = f7_2 * (int64_t) g9_19;
+  int64_t f8g0    = f8   * (int64_t) g0;
+  int64_t f8g1    = f8   * (int64_t) g1;
+  int64_t f8g2_19 = f8   * (int64_t) g2_19;
+  int64_t f8g3_19 = f8   * (int64_t) g3_19;
+  int64_t f8g4_19 = f8   * (int64_t) g4_19;
+  int64_t f8g5_19 = f8   * (int64_t) g5_19;
+  int64_t f8g6_19 = f8   * (int64_t) g6_19;
+  int64_t f8g7_19 = f8   * (int64_t) g7_19;
+  int64_t f8g8_19 = f8   * (int64_t) g8_19;
+  int64_t f8g9_19 = f8   * (int64_t) g9_19;
+  int64_t f9g0    = f9   * (int64_t) g0;
+  int64_t f9g1_38 = f9_2 * (int64_t) g1_19;
+  int64_t f9g2_19 = f9   * (int64_t) g2_19;
+  int64_t f9g3_38 = f9_2 * (int64_t) g3_19;
+  int64_t f9g4_19 = f9   * (int64_t) g4_19;
+  int64_t f9g5_38 = f9_2 * (int64_t) g5_19;
+  int64_t f9g6_19 = f9   * (int64_t) g6_19;
+  int64_t f9g7_38 = f9_2 * (int64_t) g7_19;
+  int64_t f9g8_19 = f9   * (int64_t) g8_19;
+  int64_t f9g9_38 = f9_2 * (int64_t) g9_19;
+  int64_t h0 = f0g0+f1g9_38+f2g8_19+f3g7_38+f4g6_19+f5g5_38+f6g4_19+f7g3_38+f8g2_19+f9g1_38;
+  int64_t h1 = f0g1+f1g0   +f2g9_19+f3g8_19+f4g7_19+f5g6_19+f6g5_19+f7g4_19+f8g3_19+f9g2_19;
+  int64_t h2 = f0g2+f1g1_2 +f2g0   +f3g9_38+f4g8_19+f5g7_38+f6g6_19+f7g5_38+f8g4_19+f9g3_38;
+  int64_t h3 = f0g3+f1g2   +f2g1   +f3g0   +f4g9_19+f5g8_19+f6g7_19+f7g6_19+f8g5_19+f9g4_19;
+  int64_t h4 = f0g4+f1g3_2 +f2g2   +f3g1_2 +f4g0   +f5g9_38+f6g8_19+f7g7_38+f8g6_19+f9g5_38;
+  int64_t h5 = f0g5+f1g4   +f2g3   +f3g2   +f4g1   +f5g0   +f6g9_19+f7g8_19+f8g7_19+f9g6_19;
+  int64_t h6 = f0g6+f1g5_2 +f2g4   +f3g3_2 +f4g2   +f5g1_2 +f6g0   +f7g9_38+f8g8_19+f9g7_38;
+  int64_t h7 = f0g7+f1g6   +f2g5   +f3g4   +f4g3   +f5g2   +f6g1   +f7g0   +f8g9_19+f9g8_19;
+  int64_t h8 = f0g8+f1g7_2 +f2g6   +f3g5_2 +f4g4   +f5g3_2 +f6g2   +f7g1_2 +f8g0   +f9g9_38;
+  int64_t h9 = f0g9+f1g8   +f2g7   +f3g6   +f4g5   +f5g4   +f6g3   +f7g2   +f8g1   +f9g0   ;
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+
+  /*
+  |h0| <= (1.65*1.65*2^52*(1+19+19+19+19)+1.65*1.65*2^50*(38+38+38+38+38))
+    i.e. |h0| <= 1.4*2^60; narrower ranges for h2, h4, h6, h8
+  |h1| <= (1.65*1.65*2^51*(1+1+19+19+19+19+19+19+19+19))
+    i.e. |h1| <= 1.7*2^59; narrower ranges for h3, h5, h7, h9
+  */
+
+  carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+  carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+  /* |h0| <= 2^25 */
+  /* |h4| <= 2^25 */
+  /* |h1| <= 1.71*2^59 */
+  /* |h5| <= 1.71*2^59 */
+
+  carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+  carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+  /* |h1| <= 2^24; from now on fits into int32 */
+  /* |h5| <= 2^24; from now on fits into int32 */
+  /* |h2| <= 1.41*2^60 */
+  /* |h6| <= 1.41*2^60 */
+
+  carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+  carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+  /* |h2| <= 2^25; from now on fits into int32 unchanged */
+  /* |h6| <= 2^25; from now on fits into int32 unchanged */
+  /* |h3| <= 1.71*2^59 */
+  /* |h7| <= 1.71*2^59 */
+
+  carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+  carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+  /* |h3| <= 2^24; from now on fits into int32 unchanged */
+  /* |h7| <= 2^24; from now on fits into int32 unchanged */
+  /* |h4| <= 1.72*2^34 */
+  /* |h8| <= 1.41*2^60 */
+
+  carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+  carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+  /* |h4| <= 2^25; from now on fits into int32 unchanged */
+  /* |h8| <= 2^25; from now on fits into int32 unchanged */
+  /* |h5| <= 1.01*2^24 */
+  /* |h9| <= 1.71*2^59 */
+
+  carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+  /* |h9| <= 2^24; from now on fits into int32 unchanged */
+  /* |h0| <= 1.1*2^39 */
+
+  carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+  /* |h0| <= 2^25; from now on fits into int32 unchanged */
+  /* |h1| <= 1.01*2^24 */
+
+  h[0] = h0;
+  h[1] = h1;
+  h[2] = h2;
+  h[3] = h3;
+  h[4] = h4;
+  h[5] = h5;
+  h[6] = h6;
+  h[7] = h7;
+  h[8] = h8;
+  h[9] = h9;
+}
+
+/* From fe_neg.c */
+
+/*
+h = -f
+
+Preconditions:
+   |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+
+Postconditions:
+   |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+*/
+
+//x
+static void fe_neg(fe h, const fe f) {
+  int32_t f0 = f[0];
+  int32_t f1 = f[1];
+  int32_t f2 = f[2];
+  int32_t f3 = f[3];
+  int32_t f4 = f[4];
+  int32_t f5 = f[5];
+  int32_t f6 = f[6];
+  int32_t f7 = f[7];
+  int32_t f8 = f[8];
+  int32_t f9 = f[9];
+  int32_t h0 = -f0;
+  int32_t h1 = -f1;
+  int32_t h2 = -f2;
+  int32_t h3 = -f3;
+  int32_t h4 = -f4;
+  int32_t h5 = -f5;
+  int32_t h6 = -f6;
+  int32_t h7 = -f7;
+  int32_t h8 = -f8;
+  int32_t h9 = -f9;
+  h[0] = h0;
+  h[1] = h1;
+  h[2] = h2;
+  h[3] = h3;
+  h[4] = h4;
+  h[5] = h5;
+  h[6] = h6;
+  h[7] = h7;
+  h[8] = h8;
+  h[9] = h9;
+}
+
+/* From fe_sq.c */
+
+/*
+h = f * f
+Can overlap h with f.
+
+Preconditions:
+   |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+
+Postconditions:
+   |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
+*/
+
+/*
+See fe_mul.c for discussion of implementation strategy.
+*/
+
+static void fe_sq(fe h, const fe f) {
+  int32_t f0 = f[0];
+  int32_t f1 = f[1];
+  int32_t f2 = f[2];
+  int32_t f3 = f[3];
+  int32_t f4 = f[4];
+  int32_t f5 = f[5];
+  int32_t f6 = f[6];
+  int32_t f7 = f[7];
+  int32_t f8 = f[8];
+  int32_t f9 = f[9];
+  int32_t f0_2 = 2 * f0;
+  int32_t f1_2 = 2 * f1;
+  int32_t f2_2 = 2 * f2;
+  int32_t f3_2 = 2 * f3;
+  int32_t f4_2 = 2 * f4;
+  int32_t f5_2 = 2 * f5;
+  int32_t f6_2 = 2 * f6;
+  int32_t f7_2 = 2 * f7;
+  int32_t f5_38 = 38 * f5; /* 1.959375*2^30 */
+  int32_t f6_19 = 19 * f6; /* 1.959375*2^30 */
+  int32_t f7_38 = 38 * f7; /* 1.959375*2^30 */
+  int32_t f8_19 = 19 * f8; /* 1.959375*2^30 */
+  int32_t f9_38 = 38 * f9; /* 1.959375*2^30 */
+  int64_t f0f0    = f0   * (int64_t) f0;
+  int64_t f0f1_2  = f0_2 * (int64_t) f1;
+  int64_t f0f2_2  = f0_2 * (int64_t) f2;
+  int64_t f0f3_2  = f0_2 * (int64_t) f3;
+  int64_t f0f4_2  = f0_2 * (int64_t) f4;
+  int64_t f0f5_2  = f0_2 * (int64_t) f5;
+  int64_t f0f6_2  = f0_2 * (int64_t) f6;
+  int64_t f0f7_2  = f0_2 * (int64_t) f7;
+  int64_t f0f8_2  = f0_2 * (int64_t) f8;
+  int64_t f0f9_2  = f0_2 * (int64_t) f9;
+  int64_t f1f1_2  = f1_2 * (int64_t) f1;
+  int64_t f1f2_2  = f1_2 * (int64_t) f2;
+  int64_t f1f3_4  = f1_2 * (int64_t) f3_2;
+  int64_t f1f4_2  = f1_2 * (int64_t) f4;
+  int64_t f1f5_4  = f1_2 * (int64_t) f5_2;
+  int64_t f1f6_2  = f1_2 * (int64_t) f6;
+  int64_t f1f7_4  = f1_2 * (int64_t) f7_2;
+  int64_t f1f8_2  = f1_2 * (int64_t) f8;
+  int64_t f1f9_76 = f1_2 * (int64_t) f9_38;
+  int64_t f2f2    = f2   * (int64_t) f2;
+  int64_t f2f3_2  = f2_2 * (int64_t) f3;
+  int64_t f2f4_2  = f2_2 * (int64_t) f4;
+  int64_t f2f5_2  = f2_2 * (int64_t) f5;
+  int64_t f2f6_2  = f2_2 * (int64_t) f6;
+  int64_t f2f7_2  = f2_2 * (int64_t) f7;
+  int64_t f2f8_38 = f2_2 * (int64_t) f8_19;
+  int64_t f2f9_38 = f2   * (int64_t) f9_38;
+  int64_t f3f3_2  = f3_2 * (int64_t) f3;
+  int64_t f3f4_2  = f3_2 * (int64_t) f4;
+  int64_t f3f5_4  = f3_2 * (int64_t) f5_2;
+  int64_t f3f6_2  = f3_2 * (int64_t) f6;
+  int64_t f3f7_76 = f3_2 * (int64_t) f7_38;
+  int64_t f3f8_38 = f3_2 * (int64_t) f8_19;
+  int64_t f3f9_76 = f3_2 * (int64_t) f9_38;
+  int64_t f4f4    = f4   * (int64_t) f4;
+  int64_t f4f5_2  = f4_2 * (int64_t) f5;
+  int64_t f4f6_38 = f4_2 * (int64_t) f6_19;
+  int64_t f4f7_38 = f4   * (int64_t) f7_38;
+  int64_t f4f8_38 = f4_2 * (int64_t) f8_19;
+  int64_t f4f9_38 = f4   * (int64_t) f9_38;
+  int64_t f5f5_38 = f5   * (int64_t) f5_38;
+  int64_t f5f6_38 = f5_2 * (int64_t) f6_19;
+  int64_t f5f7_76 = f5_2 * (int64_t) f7_38;
+  int64_t f5f8_38 = f5_2 * (int64_t) f8_19;
+  int64_t f5f9_76 = f5_2 * (int64_t) f9_38;
+  int64_t f6f6_19 = f6   * (int64_t) f6_19;
+  int64_t f6f7_38 = f6   * (int64_t) f7_38;
+  int64_t f6f8_38 = f6_2 * (int64_t) f8_19;
+  int64_t f6f9_38 = f6   * (int64_t) f9_38;
+  int64_t f7f7_38 = f7   * (int64_t) f7_38;
+  int64_t f7f8_38 = f7_2 * (int64_t) f8_19;
+  int64_t f7f9_76 = f7_2 * (int64_t) f9_38;
+  int64_t f8f8_19 = f8   * (int64_t) f8_19;
+  int64_t f8f9_38 = f8   * (int64_t) f9_38;
+  int64_t f9f9_38 = f9   * (int64_t) f9_38;
+  int64_t h0 = f0f0  +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38;
+  int64_t h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38;
+  int64_t h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19;
+  int64_t h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38;
+  int64_t h4 = f0f4_2+f1f3_4 +f2f2   +f5f9_76+f6f8_38+f7f7_38;
+  int64_t h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38;
+  int64_t h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19;
+  int64_t h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38;
+  int64_t h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4   +f9f9_38;
+  int64_t h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2;
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+
+  carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+  carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+
+  carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+  carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+
+  carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+  carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+
+  carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+  carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+  carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+  carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+  carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+
+  carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+
+  h[0] = h0;
+  h[1] = h1;
+  h[2] = h2;
+  h[3] = h3;
+  h[4] = h4;
+  h[5] = h5;
+  h[6] = h6;
+  h[7] = h7;
+  h[8] = h8;
+  h[9] = h9;
+}
+
+/* From fe_sq2.c */
+
+/*
+h = 2 * f * f
+Can overlap h with f.
+
+Preconditions:
+   |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+
+Postconditions:
+   |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
+*/
+
+/*
+See fe_mul.c for discussion of implementation strategy.
+*/
+
+static void fe_sq2(fe h, const fe f) {
+  int32_t f0 = f[0];
+  int32_t f1 = f[1];
+  int32_t f2 = f[2];
+  int32_t f3 = f[3];
+  int32_t f4 = f[4];
+  int32_t f5 = f[5];
+  int32_t f6 = f[6];
+  int32_t f7 = f[7];
+  int32_t f8 = f[8];
+  int32_t f9 = f[9];
+  int32_t f0_2 = 2 * f0;
+  int32_t f1_2 = 2 * f1;
+  int32_t f2_2 = 2 * f2;
+  int32_t f3_2 = 2 * f3;
+  int32_t f4_2 = 2 * f4;
+  int32_t f5_2 = 2 * f5;
+  int32_t f6_2 = 2 * f6;
+  int32_t f7_2 = 2 * f7;
+  int32_t f5_38 = 38 * f5; /* 1.959375*2^30 */
+  int32_t f6_19 = 19 * f6; /* 1.959375*2^30 */
+  int32_t f7_38 = 38 * f7; /* 1.959375*2^30 */
+  int32_t f8_19 = 19 * f8; /* 1.959375*2^30 */
+  int32_t f9_38 = 38 * f9; /* 1.959375*2^30 */
+  int64_t f0f0    = f0   * (int64_t) f0;
+  int64_t f0f1_2  = f0_2 * (int64_t) f1;
+  int64_t f0f2_2  = f0_2 * (int64_t) f2;
+  int64_t f0f3_2  = f0_2 * (int64_t) f3;
+  int64_t f0f4_2  = f0_2 * (int64_t) f4;
+  int64_t f0f5_2  = f0_2 * (int64_t) f5;
+  int64_t f0f6_2  = f0_2 * (int64_t) f6;
+  int64_t f0f7_2  = f0_2 * (int64_t) f7;
+  int64_t f0f8_2  = f0_2 * (int64_t) f8;
+  int64_t f0f9_2  = f0_2 * (int64_t) f9;
+  int64_t f1f1_2  = f1_2 * (int64_t) f1;
+  int64_t f1f2_2  = f1_2 * (int64_t) f2;
+  int64_t f1f3_4  = f1_2 * (int64_t) f3_2;
+  int64_t f1f4_2  = f1_2 * (int64_t) f4;
+  int64_t f1f5_4  = f1_2 * (int64_t) f5_2;
+  int64_t f1f6_2  = f1_2 * (int64_t) f6;
+  int64_t f1f7_4  = f1_2 * (int64_t) f7_2;
+  int64_t f1f8_2  = f1_2 * (int64_t) f8;
+  int64_t f1f9_76 = f1_2 * (int64_t) f9_38;
+  int64_t f2f2    = f2   * (int64_t) f2;
+  int64_t f2f3_2  = f2_2 * (int64_t) f3;
+  int64_t f2f4_2  = f2_2 * (int64_t) f4;
+  int64_t f2f5_2  = f2_2 * (int64_t) f5;
+  int64_t f2f6_2  = f2_2 * (int64_t) f6;
+  int64_t f2f7_2  = f2_2 * (int64_t) f7;
+  int64_t f2f8_38 = f2_2 * (int64_t) f8_19;
+  int64_t f2f9_38 = f2   * (int64_t) f9_38;
+  int64_t f3f3_2  = f3_2 * (int64_t) f3;
+  int64_t f3f4_2  = f3_2 * (int64_t) f4;
+  int64_t f3f5_4  = f3_2 * (int64_t) f5_2;
+  int64_t f3f6_2  = f3_2 * (int64_t) f6;
+  int64_t f3f7_76 = f3_2 * (int64_t) f7_38;
+  int64_t f3f8_38 = f3_2 * (int64_t) f8_19;
+  int64_t f3f9_76 = f3_2 * (int64_t) f9_38;
+  int64_t f4f4    = f4   * (int64_t) f4;
+  int64_t f4f5_2  = f4_2 * (int64_t) f5;
+  int64_t f4f6_38 = f4_2 * (int64_t) f6_19;
+  int64_t f4f7_38 = f4   * (int64_t) f7_38;
+  int64_t f4f8_38 = f4_2 * (int64_t) f8_19;
+  int64_t f4f9_38 = f4   * (int64_t) f9_38;
+  int64_t f5f5_38 = f5   * (int64_t) f5_38;
+  int64_t f5f6_38 = f5_2 * (int64_t) f6_19;
+  int64_t f5f7_76 = f5_2 * (int64_t) f7_38;
+  int64_t f5f8_38 = f5_2 * (int64_t) f8_19;
+  int64_t f5f9_76 = f5_2 * (int64_t) f9_38;
+  int64_t f6f6_19 = f6   * (int64_t) f6_19;
+  int64_t f6f7_38 = f6   * (int64_t) f7_38;
+  int64_t f6f8_38 = f6_2 * (int64_t) f8_19;
+  int64_t f6f9_38 = f6   * (int64_t) f9_38;
+  int64_t f7f7_38 = f7   * (int64_t) f7_38;
+  int64_t f7f8_38 = f7_2 * (int64_t) f8_19;
+  int64_t f7f9_76 = f7_2 * (int64_t) f9_38;
+  int64_t f8f8_19 = f8   * (int64_t) f8_19;
+  int64_t f8f9_38 = f8   * (int64_t) f9_38;
+  int64_t f9f9_38 = f9   * (int64_t) f9_38;
+  int64_t h0 = f0f0  +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38;
+  int64_t h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38;
+  int64_t h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19;
+  int64_t h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38;
+  int64_t h4 = f0f4_2+f1f3_4 +f2f2   +f5f9_76+f6f8_38+f7f7_38;
+  int64_t h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38;
+  int64_t h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19;
+  int64_t h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38;
+  int64_t h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4   +f9f9_38;
+  int64_t h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2;
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+
+  h0 += h0;
+  h1 += h1;
+  h2 += h2;
+  h3 += h3;
+  h4 += h4;
+  h5 += h5;
+  h6 += h6;
+  h7 += h7;
+  h8 += h8;
+  h9 += h9;
+
+  carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+  carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+
+  carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+  carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+
+  carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+  carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+
+  carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+  carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+  carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+  carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+  carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+
+  carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+
+  h[0] = h0;
+  h[1] = h1;
+  h[2] = h2;
+  h[3] = h3;
+  h[4] = h4;
+  h[5] = h5;
+  h[6] = h6;
+  h[7] = h7;
+  h[8] = h8;
+  h[9] = h9;
+}
+
+/* From fe_sub.c */
+
+/*
+h = f - g
+Can overlap h with f or g.
+
+Preconditions:
+   |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+   |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+
+Postconditions:
+   |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+//x
+static void fe_sub(fe h, const fe f, const fe g) {
+  int32_t f0 = f[0];
+  int32_t f1 = f[1];
+  int32_t f2 = f[2];
+  int32_t f3 = f[3];
+  int32_t f4 = f[4];
+  int32_t f5 = f[5];
+  int32_t f6 = f[6];
+  int32_t f7 = f[7];
+  int32_t f8 = f[8];
+  int32_t f9 = f[9];
+  int32_t g0 = g[0];
+  int32_t g1 = g[1];
+  int32_t g2 = g[2];
+  int32_t g3 = g[3];
+  int32_t g4 = g[4];
+  int32_t g5 = g[5];
+  int32_t g6 = g[6];
+  int32_t g7 = g[7];
+  int32_t g8 = g[8];
+  int32_t g9 = g[9];
+  int32_t h0 = f0 - g0;
+  int32_t h1 = f1 - g1;
+  int32_t h2 = f2 - g2;
+  int32_t h3 = f3 - g3;
+  int32_t h4 = f4 - g4;
+  int32_t h5 = f5 - g5;
+  int32_t h6 = f6 - g6;
+  int32_t h7 = f7 - g7;
+  int32_t h8 = f8 - g8;
+  int32_t h9 = f9 - g9;
+  h[0] = h0;
+  h[1] = h1;
+  h[2] = h2;
+  h[3] = h3;
+  h[4] = h4;
+  h[5] = h5;
+  h[6] = h6;
+  h[7] = h7;
+  h[8] = h8;
+  h[9] = h9;
+}
+
+/* From fe_tobytes.c */
+
+/*
+Preconditions:
+  |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+
+Write p=2^255-19; q=floor(h/p).
+Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))).
+
+Proof:
+  Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4.
+  Also have |h-2^230 h9|<2^231 so |19 2^(-255)(h-2^230 h9)|<1/4.
+
+  Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9).
+  Then 0<y<1.
+
+  Write r=h-pq.
+  Have 0<=r<=p-1=2^255-20.
+  Thus 0<=r+19(2^-255)r<r+19(2^-255)2^255<=2^255-1.
+
+  Write x=r+19(2^-255)r+y.
+  Then 0<x<2^255 so floor(2^(-255)x) = 0 so floor(q+2^(-255)x) = q.
+
+  Have q+2^(-255)x = 2^(-255)(h + 19 2^(-25) h9 + 2^(-1))
+  so floor(2^(-255)(h + 19 2^(-25) h9 + 2^(-1))) = q.
+*/
+
+static void fe_tobytes(unsigned char *s, const fe h) {
+  int32_t h0 = h[0];
+  int32_t h1 = h[1];
+  int32_t h2 = h[2];
+  int32_t h3 = h[3];
+  int32_t h4 = h[4];
+  int32_t h5 = h[5];
+  int32_t h6 = h[6];
+  int32_t h7 = h[7];
+  int32_t h8 = h[8];
+  int32_t h9 = h[9];
+  int32_t q;
+  int32_t carry0;
+  int32_t carry1;
+  int32_t carry2;
+  int32_t carry3;
+  int32_t carry4;
+  int32_t carry5;
+  int32_t carry6;
+  int32_t carry7;
+  int32_t carry8;
+  int32_t carry9;
+
+  q = (19 * h9 + (((int32_t) 1) << 24)) >> 25;
+  q = (h0 + q) >> 26;
+  q = (h1 + q) >> 25;
+  q = (h2 + q) >> 26;
+  q = (h3 + q) >> 25;
+  q = (h4 + q) >> 26;
+  q = (h5 + q) >> 25;
+  q = (h6 + q) >> 26;
+  q = (h7 + q) >> 25;
+  q = (h8 + q) >> 26;
+  q = (h9 + q) >> 25;
+
+  /* Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. */
+  h0 += 19 * q;
+  /* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */
+
+  carry0 = h0 >> 26; h1 += carry0; h0 -= carry0 << 26;
+  carry1 = h1 >> 25; h2 += carry1; h1 -= carry1 << 25;
+  carry2 = h2 >> 26; h3 += carry2; h2 -= carry2 << 26;
+  carry3 = h3 >> 25; h4 += carry3; h3 -= carry3 << 25;
+  carry4 = h4 >> 26; h5 += carry4; h4 -= carry4 << 26;
+  carry5 = h5 >> 25; h6 += carry5; h5 -= carry5 << 25;
+  carry6 = h6 >> 26; h7 += carry6; h6 -= carry6 << 26;
+  carry7 = h7 >> 25; h8 += carry7; h7 -= carry7 << 25;
+  carry8 = h8 >> 26; h9 += carry8; h8 -= carry8 << 26;
+  carry9 = h9 >> 25;               h9 -= carry9 << 25;
+                  /* h10 = carry9 */
+
+  /*
+  Goal: Output h0+...+2^255 h10-2^255 q, which is between 0 and 2^255-20.
+  Have h0+...+2^230 h9 between 0 and 2^255-1;
+  evidently 2^255 h10-2^255 q = 0.
+  Goal: Output h0+...+2^230 h9.
+  */
+
+  s[0] = h0 >> 0;
+  s[1] = h0 >> 8;
+  s[2] = h0 >> 16;
+  s[3] = (h0 >> 24) | (h1 << 2);
+  s[4] = h1 >> 6;
+  s[5] = h1 >> 14;
+  s[6] = (h1 >> 22) | (h2 << 3);
+  s[7] = h2 >> 5;
+  s[8] = h2 >> 13;
+  s[9] = (h2 >> 21) | (h3 << 5);
+  s[10] = h3 >> 3;
+  s[11] = h3 >> 11;
+  s[12] = (h3 >> 19) | (h4 << 6);
+  s[13] = h4 >> 2;
+  s[14] = h4 >> 10;
+  s[15] = h4 >> 18;
+  s[16] = h5 >> 0;
+  s[17] = h5 >> 8;
+  s[18] = h5 >> 16;
+  s[19] = (h5 >> 24) | (h6 << 1);
+  s[20] = h6 >> 7;
+  s[21] = h6 >> 15;
+  s[22] = (h6 >> 23) | (h7 << 3);
+  s[23] = h7 >> 5;
+  s[24] = h7 >> 13;
+  s[25] = (h7 >> 21) | (h8 << 4);
+  s[26] = h8 >> 4;
+  s[27] = h8 >> 12;
+  s[28] = (h8 >> 20) | (h9 << 6);
+  s[29] = h9 >> 2;
+  s[30] = h9 >> 10;
+  s[31] = h9 >> 18;
+}
+
+/* From ge_add.c */
+
+//x
+void ge_add(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) {
+  fe t0;
+  fe_add(r->X, p->Y, p->X);
+  fe_sub(r->Y, p->Y, p->X);
+  fe_mul(r->Z, r->X, q->YplusX);
+  fe_mul(r->Y, r->Y, q->YminusX);
+  fe_mul(r->T, q->T2d, p->T);
+  fe_mul(r->X, p->Z, q->Z);
+  fe_add(t0, r->X, r->X);
+  fe_sub(r->X, r->Z, r->Y);
+  fe_add(r->Y, r->Z, r->Y);
+  fe_add(r->Z, t0, r->T);
+  fe_sub(r->T, t0, r->T);
+}
+
+/* From ge_double_scalarmult.c, modified */
+
+static void slide(signed char *r, const unsigned char *a) {
+  int i;
+  int b;
+  int k;
+
+  //this loop just makes a binary string out of a 
+  //e.g. a = {3, 0, 0, ...} then r = 110000....
+  for (i = 0; i < 256; ++i) {
+    r[i] = 1 & (a[i >> 3] >> (i & 7));
+  }
+
+  for (i = 0; i < 256; ++i) {
+    if (r[i]) {
+      for (b = 1; b <= 6 && i + b < 256; ++b) {
+        if (r[i + b]) {
+          if (r[i] + (r[i + b] << b) <= 15) {
+            r[i] += r[i + b] << b; r[i + b] = 0;
+          } else if (r[i] - (r[i + b] << b) >= -15) {
+            r[i] -= r[i + b] << b;
+            for (k = i + b; k < 256; ++k) {
+              if (!r[k]) {
+                r[k] = 1;
+                break;
+              }
+              r[k] = 0;
+            }
+          } else
+            break;
+        }
+      }
+    }
+  }
+}
+
+//double scalar mult precomp
+void ge_dsm_precomp(ge_dsmp r, const ge_p3 *s) {
+  ge_p1p1 t;
+  ge_p3 s2, u;
+  ge_p3_to_cached(&r[0], s);
+  ge_p3_dbl(&t, s); ge_p1p1_to_p3(&s2, &t);
+  ge_add(&t, &s2, &r[0]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&r[1], &u);
+  ge_add(&t, &s2, &r[1]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&r[2], &u);
+  ge_add(&t, &s2, &r[2]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&r[3], &u);
+  ge_add(&t, &s2, &r[3]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&r[4], &u);
+  ge_add(&t, &s2, &r[4]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&r[5], &u);
+  ge_add(&t, &s2, &r[5]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&r[6], &u);
+  ge_add(&t, &s2, &r[6]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&r[7], &u);
+}
+
+/*
+r = a * A + b * B
+where a = a[0]+256*a[1]+...+256^31 a[31].
+and b = b[0]+256*b[1]+...+256^31 b[31].
+B is the Ed25519 base point (x,4/5) with x positive.
+*/
+
+//this is a really simple alg. actually
+void ge_double_scalarmult_base_vartime(ge_p2 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b) {
+  signed char aslide[256];
+  signed char bslide[256];
+  ge_dsmp Ai; /* A, 3A, 5A, 7A, 9A, 11A, 13A, 15A */
+  ge_p1p1 t;
+  ge_p3 u;
+  int i;
+
+  slide(aslide, a);
+  slide(bslide, b);
+  ge_dsm_precomp(Ai, A);/* A, 3A, 5A, 7A, 9A, 11A, 13A, 15A */
+
+  ge_p2_0(r);
+
+  for (i = 255; i >= 0; --i) {
+      //so this gets us to the highest i such that both have a nonzero
+    if (aslide[i] || bslide[i]) break;
+  }
+
+  for (; i >= 0; --i) {
+    ge_p2_dbl(&t, r);//simple double and add
+
+    if (aslide[i] > 0) {
+      ge_p1p1_to_p3(&u, &t);
+      ge_add(&t, &u, &Ai[aslide[i]/2]);
+    } else if (aslide[i] < 0) {
+      ge_p1p1_to_p3(&u, &t);
+      ge_sub(&t, &u, &Ai[(-aslide[i])/2]);
+    }
+
+    if (bslide[i] > 0) {
+      ge_p1p1_to_p3(&u, &t);
+      ge_madd(&t, &u, &ge_Bi[bslide[i]/2]);
+    } else if (bslide[i] < 0) {
+      ge_p1p1_to_p3(&u, &t);
+      ge_msub(&t, &u, &ge_Bi[(-bslide[i])/2]);
+    }
+
+    ge_p1p1_to_p2(r, &t);
+  }
+}
+
+/* From ge_frombytes.c, modified */
+//this is like xrecover .. 
+//x
+int ge_frombytes_vartime(ge_p3 *h, const unsigned char *s) {
+  fe u;
+  fe v;
+  fe vxx;
+  fe check;
+
+  /* From fe_frombytes.c */
+
+  int64_t h0 = load_4(s);
+  int64_t h1 = load_3(s + 4) << 6;
+  int64_t h2 = load_3(s + 7) << 5;
+  int64_t h3 = load_3(s + 10) << 3;
+  int64_t h4 = load_3(s + 13) << 2;
+  int64_t h5 = load_4(s + 16);
+  int64_t h6 = load_3(s + 20) << 7;
+  int64_t h7 = load_3(s + 23) << 5;
+  int64_t h8 = load_3(s + 26) << 4;
+  int64_t h9 = (load_3(s + 29) & 8388607) << 2;
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+
+  /* Validate the number to be canonical */
+  if (h9 == 33554428 && h8 == 268435440 && h7 == 536870880 && h6 == 2147483520 &&
+    h5 == 4294967295 && h4 == 67108860 && h3 == 134217720 && h2 == 536870880 &&
+    h1 == 1073741760 && h0 >= 4294967277) {
+    return -1;
+  }
+
+  carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+  carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+  carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+  carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+  carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+  carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+  carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+  carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+  carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+  carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+  h->Y[0] = h0;
+  h->Y[1] = h1;
+  h->Y[2] = h2;
+  h->Y[3] = h3;
+  h->Y[4] = h4;
+  h->Y[5] = h5;
+  h->Y[6] = h6;
+  h->Y[7] = h7;
+  h->Y[8] = h8;
+  h->Y[9] = h9;
+
+  /* End fe_frombytes.c */
+
+  fe_1(h->Z);
+  fe_sq(u, h->Y);
+  fe_mul(v, u, fe_d);
+  fe_sub(u, u, h->Z);       /* u = y^2-1 */
+  fe_add(v, v, h->Z);       /* v = dy^2+1 */
+
+  fe_divpowm1(h->X, u, v); /* x = uv^3(uv^7)^((q-5)/8) */
+
+  fe_sq(vxx, h->X);
+  fe_mul(vxx, vxx, v);
+  fe_sub(check, vxx, u);    /* vx^2-u */
+  if (fe_isnonzero(check)) {
+    fe_add(check, vxx, u);  /* vx^2+u */
+    if (fe_isnonzero(check)) {
+      return -1;
+    }
+    fe_mul(h->X, h->X, fe_sqrtm1); //this is mapping X to X * sqrt(-1) c.f. 3.1 in hisil, dong, etc. 
+  }
+
+  if (fe_isnegative(h->X) != (s[31] >> 7)) {
+    /* If x = 0, the sign must be positive */
+    if (!fe_isnonzero(h->X)) {
+      return -1;
+    }
+    fe_neg(h->X, h->X);
+  }
+
+  fe_mul(h->T, h->X, h->Y);
+  return 0;
+}
+
+/* From ge_madd.c */
+
+/*
+r = p + q
+*/
+
+//x
+static void ge_madd(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) {
+  fe t0;
+  fe_add(r->X, p->Y, p->X);
+  fe_sub(r->Y, p->Y, p->X);
+  fe_mul(r->Z, r->X, q->yplusx);
+  fe_mul(r->Y, r->Y, q->yminusx);
+  fe_mul(r->T, q->xy2d, p->T);
+  fe_add(t0, p->Z, p->Z);
+  fe_sub(r->X, r->Z, r->Y);
+  fe_add(r->Y, r->Z, r->Y);
+  fe_add(r->Z, t0, r->T);
+  fe_sub(r->T, t0, r->T);
+}
+
+/* From ge_msub.c */
+
+/*
+r = p - q
+*/
+
+//x
+static void ge_msub(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) {
+  fe t0;
+  fe_add(r->X, p->Y, p->X);
+  fe_sub(r->Y, p->Y, p->X);
+  fe_mul(r->Z, r->X, q->yminusx);
+  fe_mul(r->Y, r->Y, q->yplusx);
+  fe_mul(r->T, q->xy2d, p->T);
+  fe_add(t0, p->Z, p->Z);
+  fe_sub(r->X, r->Z, r->Y);
+  fe_add(r->Y, r->Z, r->Y);
+  fe_sub(r->Z, t0, r->T);
+  fe_add(r->T, t0, r->T);
+}
+
+/* From ge_p1p1_to_p2.c */
+
+/*
+r = p
+*/
+
+//x
+void ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p) {
+  fe_mul(r->X, p->X, p->T);
+  fe_mul(r->Y, p->Y, p->Z);
+  fe_mul(r->Z, p->Z, p->T);
+}
+
+/* From ge_p1p1_to_p3.c */
+
+/*
+r = p
+*/
+
+//x
+void ge_p1p1_to_p3(ge_p3 *r, const ge_p1p1 *p) {
+  fe_mul(r->X, p->X, p->T);
+  fe_mul(r->Y, p->Y, p->Z);
+  fe_mul(r->Z, p->Z, p->T);
+  fe_mul(r->T, p->X, p->Y);
+}
+
+/* From ge_p2_0.c */
+
+//x
+static void ge_p2_0(ge_p2 *h) {
+  fe_0(h->X);
+  fe_1(h->Y);
+  fe_1(h->Z);
+}
+
+/* From ge_p2_dbl.c */
+
+/*
+r = 2 * p
+*/
+
+//x
+void ge_p2_dbl(ge_p1p1 *r, const ge_p2 *p) {
+  fe t0;
+  fe_sq(r->X, p->X);
+  fe_sq(r->Z, p->Y);
+  fe_sq2(r->T, p->Z);
+  fe_add(r->Y, p->X, p->Y);
+  fe_sq(t0, r->Y);
+  fe_add(r->Y, r->Z, r->X);
+  fe_sub(r->Z, r->Z, r->X);
+  fe_sub(r->X, t0, r->Y);
+  fe_sub(r->T, r->T, r->Z);
+}
+
+/* From ge_p3_0.c */
+
+//x
+static void ge_p3_0(ge_p3 *h) {
+  fe_0(h->X);
+  fe_1(h->Y);
+  fe_1(h->Z);
+  fe_0(h->T);
+}
+
+/* From ge_p3_dbl.c */
+
+/*
+r = 2 * p
+*/
+
+//x
+static void ge_p3_dbl(ge_p1p1 *r, const ge_p3 *p) {
+  ge_p2 q;
+  ge_p3_to_p2(&q, p);
+  ge_p2_dbl(r, &q);
+}
+
+/* From ge_p3_to_cached.c */
+
+/*
+r = p
+*/
+
+//x
+void ge_p3_to_cached(ge_cached *r, const ge_p3 *p) {
+  fe_add(r->YplusX, p->Y, p->X);
+  fe_sub(r->YminusX, p->Y, p->X);
+  fe_copy(r->Z, p->Z);
+  fe_mul(r->T2d, p->T, fe_d2);
+}
+
+/* From ge_p3_to_p2.c */
+
+/*
+r = p
+*/
+
+//x
+void ge_p3_to_p2(ge_p2 *r, const ge_p3 *p) {
+  fe_copy(r->X, p->X);
+  fe_copy(r->Y, p->Y);
+  fe_copy(r->Z, p->Z);
+}
+
+/* From ge_p3_tobytes.c */
+
+//x
+void ge_p3_tobytes(unsigned char *s, const ge_p3 *h) {
+  fe recip;
+  fe x;
+  fe y;
+
+  fe_invert(recip, h->Z);
+  fe_mul(x, h->X, recip);
+  fe_mul(y, h->Y, recip);
+  fe_tobytes(s, y);
+  s[31] ^= fe_isnegative(x) << 7;
+}
+
+/* From ge_precomp_0.c */
+
+//x
+static void ge_precomp_0(ge_precomp *h) {
+  fe_1(h->yplusx);
+  fe_1(h->yminusx);
+  fe_0(h->xy2d);
+}
+
+/* From ge_scalarmult_base.c */
+
+//x
+static unsigned char equal(signed char b, signed char c) {
+  unsigned char ub = b;
+  unsigned char uc = c;
+  unsigned char x = ub ^ uc; /* 0: yes; 1..255: no */
+  uint32_t y = x; /* 0: yes; 1..255: no */
+  y -= 1; /* 4294967295: yes; 0..254: no */
+  y >>= 31; /* 1: yes; 0: no */
+  return y;
+}
+
+static unsigned char negative(signed char b) {
+  unsigned long long x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */
+  x >>= 63; /* 1: yes; 0: no */
+  return x;
+}
+
+static void ge_precomp_cmov(ge_precomp *t, const ge_precomp *u, unsigned char b) {
+  fe_cmov(t->yplusx, u->yplusx, b);
+  fe_cmov(t->yminusx, u->yminusx, b);
+  fe_cmov(t->xy2d, u->xy2d, b);
+}
+
+static void select(ge_precomp *t, int pos, signed char b) {
+  ge_precomp minust;
+  unsigned char bnegative = negative(b);
+  unsigned char babs = b - (((-bnegative) & b) << 1);
+
+  ge_precomp_0(t);
+  ge_precomp_cmov(t, &ge_base[pos][0], equal(babs, 1));
+  ge_precomp_cmov(t, &ge_base[pos][1], equal(babs, 2));
+  ge_precomp_cmov(t, &ge_base[pos][2], equal(babs, 3));
+  ge_precomp_cmov(t, &ge_base[pos][3], equal(babs, 4));
+  ge_precomp_cmov(t, &ge_base[pos][4], equal(babs, 5));
+  ge_precomp_cmov(t, &ge_base[pos][5], equal(babs, 6));
+  ge_precomp_cmov(t, &ge_base[pos][6], equal(babs, 7));
+  ge_precomp_cmov(t, &ge_base[pos][7], equal(babs, 8));
+  fe_copy(minust.yplusx, t->yminusx);
+  fe_copy(minust.yminusx, t->yplusx);
+  fe_neg(minust.xy2d, t->xy2d);
+  ge_precomp_cmov(t, &minust, bnegative);
+}
+
+/*
+h = a * B
+where a = a[0]+256*a[1]+...+256^31 a[31]
+B is the Ed25519 base point (x,4/5) with x positive.
+
+Preconditions:
+  a[31] <= 127
+*/
+
+void ge_scalarmult_base(ge_p3 *h, const unsigned char *a) {
+  signed char e[64];
+  signed char carry;
+  ge_p1p1 r;
+  ge_p2 s;
+  ge_precomp t;
+  int i;
+
+  for (i = 0; i < 32; ++i) {
+    e[2 * i + 0] = (a[i] >> 0) & 15;
+    e[2 * i + 1] = (a[i] >> 4) & 15;
+  }
+  /* each e[i] is between 0 and 15 */
+  /* e[63] is between 0 and 7 */
+
+  carry = 0;
+  for (i = 0; i < 63; ++i) {
+    e[i] += carry;
+    carry = e[i] + 8;
+    carry >>= 4;
+    e[i] -= carry << 4;
+  }
+  e[63] += carry;
+  /* each e[i] is between -8 and 8 */
+
+  ge_p3_0(h);
+  //note, these are indexing from 1, 3, 5, etc. 
+  for (i = 1; i < 64; i += 2) {
+    select(&t, i / 2, e[i]); //here's where you grab multiples of the basepoint .. 
+    //so must be doing e P = (e[0] (2^4)^0 P + e[1] (2^4)^1 P + e[2] (2^4)^2 P + ...)
+    //except, probably writing in big-endian to make more sense..
+    //and the e[i] P are going to be pre-computed...
+    //so have to wonder if by precomputing more, if can save time??
+    ge_madd(&r, h, &t); ge_p1p1_to_p3(h, &r);
+  }
+
+  ge_p3_dbl(&r, h);  ge_p1p1_to_p2(&s, &r);
+  ge_p2_dbl(&r, &s); ge_p1p1_to_p2(&s, &r);
+  ge_p2_dbl(&r, &s); ge_p1p1_to_p2(&s, &r);
+  ge_p2_dbl(&r, &s); ge_p1p1_to_p3(h, &r);
+
+  //note, these are indexing from 0, 2, 4, etc. 
+  for (i = 0; i < 64; i += 2) {
+    select(&t, i / 2, e[i]);
+    ge_madd(&r, h, &t); ge_p1p1_to_p3(h, &r);
+  }
+}
+
+/* From ge_sub.c */
+
+/*
+r = p - q
+*/
+
+//x
+static void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) {
+  fe t0;
+  fe_add(r->X, p->Y, p->X);
+  fe_sub(r->Y, p->Y, p->X);
+  fe_mul(r->Z, r->X, q->YminusX);
+  fe_mul(r->Y, r->Y, q->YplusX);
+  fe_mul(r->T, q->T2d, p->T);
+  fe_mul(r->X, p->Z, q->Z);
+  fe_add(t0, r->X, r->X);
+  fe_sub(r->X, r->Z, r->Y);
+  fe_add(r->Y, r->Z, r->Y);
+  fe_sub(r->Z, t0, r->T);
+  fe_add(r->T, t0, r->T);
+}
+
+/* From ge_tobytes.c */
+
+//x
+void ge_tobytes(unsigned char *s, const ge_p2 *h) {
+  fe recip;
+  fe x;
+  fe y;
+
+  fe_invert(recip, h->Z);
+  fe_mul(x, h->X, recip);
+  fe_mul(y, h->Y, recip);
+  fe_tobytes(s, y);
+  s[31] ^= fe_isnegative(x) << 7;
+}
+
+/* From sc_reduce.c */
+
+/*
+Input:
+  s[0]+256*s[1]+...+256^63*s[63] = s
+
+Output:
+  s[0]+256*s[1]+...+256^31*s[31] = s mod l
+  where l = 2^252 + 27742317777372353535851937790883648493.
+  Overwrites s in place.
+*/
+
+//x
+void sc_reduce(unsigned char *s) {
+  //the point is to load in 21 bits at a time..
+  //Mininero should give you the ints 2097151, the shifts below, and either load 3 or 4
+  int64_t s0 = 2097151 & load_3(s); //2097151 is 21 1's in binary, so there are possible 5 bits left over.. 
+  int64_t s1 = 2097151 & (load_4(s + 2) >> 5); //now you start at 2^16, so you have to move right 5 bits to 2^21.., the 2 comes from the fact that you loaded 3 last time..
+  int64_t s2 = 2097151 & (load_3(s + 5) >> 2); //in last one you had bits 22 ->42, you are starting at (2^8)^5 = 2^40, so need to move right 2 bits...
+  int64_t s3 = 2097151 & (load_4(s + 7) >> 7); //etc...
+  int64_t s4 = 2097151 & (load_4(s + 10) >> 4); //ahh, these are "int 64;s"
+  int64_t s5 = 2097151 & (load_3(s + 13) >> 1); //not uint 64s
+  int64_t s6 = 2097151 & (load_4(s + 15) >> 6);
+  int64_t s7 = 2097151 & (load_3(s + 18) >> 3);
+  int64_t s8 = 2097151 & load_3(s + 21);
+  int64_t s9 = 2097151 & (load_4(s + 23) >> 5);
+  int64_t s10 = 2097151 & (load_3(s + 26) >> 2);
+  int64_t s11 = 2097151 & (load_4(s + 28) >> 7);
+  int64_t s12 = 2097151 & (load_4(s + 31) >> 4);
+  int64_t s13 = 2097151 & (load_3(s + 34) >> 1);
+  int64_t s14 = 2097151 & (load_4(s + 36) >> 6);
+  int64_t s15 = 2097151 & (load_3(s + 39) >> 3);
+  int64_t s16 = 2097151 & load_3(s + 42);
+  int64_t s17 = 2097151 & (load_4(s + 44) >> 5);
+  int64_t s18 = 2097151 & (load_3(s + 47) >> 2);
+  int64_t s19 = 2097151 & (load_4(s + 49) >> 7);
+  int64_t s20 = 2097151 & (load_4(s + 52) >> 4);
+  int64_t s21 = 2097151 & (load_3(s + 55) >> 1);
+  int64_t s22 = 2097151 & (load_4(s + 57) >> 6);
+  int64_t s23 = (load_4(s + 60) >> 3); //note no &2097151 here .. 
+                                       //so rather than doing 24 = 512 
+                                       //we've done 23 = 504 
+                                       //so curve size rather than
+                                       //size of s
+                                       //this should be handled
+                                       //at the end with those
+                                       //two extra reductions
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+  int64_t carry10;
+  int64_t carry11;
+  int64_t carry12;
+  int64_t carry13;
+  int64_t carry14;
+  int64_t carry15;
+  int64_t carry16;
+  //17 carries because 11, 12, ... 16 = #digits in l
+
+  //reduce first 105 bits.. to go from 504 to 399
+  //Note that 683901 * 2^(5*21) - 136657 * 2^(4 * 21) + ... - 66643 = 27742317777372353535851937790883648493, which is c in the curve order..
+  s11 += s23 * 666643; // =1430509 - 2 ^ 21  //note there is a 12 step difference, 12^21 = 252
+                                             //so you subtract q 12^21 and then add c at each step..
+                                             //just have to be careful of the carries .. 
+                                             //If you are using unsigned int's, you had better carry at each step
+                                             //so the first step is to factorize 252 and whatever radix
+                                             //must be in those factors.. 
+  s12 += s23 * 470296; // = 1626855 - 2^21 - 1
+  s13 += s23 * 654183; // = 1442968 - 2 ^ 21 - 1?
+  s14 -= s23 * 997805; //note the negative ones are same as result from toDigits
+  s15 += s23 * 136657; // 1960495 - 2 ** 21
+  s16 -= s23 * 683901; //note negative ones are same 
+
+  s10 += s22 * 666643; //22 - 10 = 12, 12 * 21 = 252 
+  s11 += s22 * 470296;
+  s12 += s22 * 654183;
+  s13 -= s22 * 997805;
+  s14 += s22 * 136657;
+  s15 -= s22 * 683901;
+
+  s9 += s21 * 666643; //21 - 9 = 12
+  s10 += s21 * 470296;
+  s11 += s21 * 654183;
+  s12 -= s21 * 997805;
+  s13 += s21 * 136657;
+  s14 -= s21 * 683901;
+
+  s8 += s20 * 666643;
+  s9 += s20 * 470296;
+  s10 += s20 * 654183;
+  s11 -= s20 * 997805;
+  s12 += s20 * 136657;
+  s13 -= s20 * 683901;
+
+  s7 += s19 * 666643;
+  s8 += s19 * 470296;
+  s9 += s19 * 654183;
+  s10 -= s19 * 997805;
+  s11 += s19 * 136657;
+  s12 -= s19 * 683901;
+
+  s6 += s18 * 666643;
+  s7 += s18 * 470296;
+  s8 += s18 * 654183;
+  s9 -= s18 * 997805;
+  s10 += s18 * 136657;
+  s11 -= s18 * 683901;
+  //so we repeat this until we get down to s11
+  //note that 11 * 21 = 231
+
+  //1st carry...
+  //note span = 6 here
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;//take parts that are more than 21 bits in new s6 and add to s7..
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
+  carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
+  carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
+
+  //span = 5 here
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+  carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
+  carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
+
+  //reduce 105 bits to go from 399 to 294
+  s5 += s17 * 666643; //17 - 5 = 12 = 252/21
+  s6 += s17 * 470296;
+  s7 += s17 * 654183;
+  s8 -= s17 * 997805;
+  s9 += s17 * 136657;
+  s10 -= s17 * 683901;
+
+  s4 += s16 * 666643;
+  s5 += s16 * 470296;
+  s6 += s16 * 654183;
+  s7 -= s16 * 997805;
+  s8 += s16 * 136657;
+  s9 -= s16 * 683901;
+
+  s3 += s15 * 666643;
+  s4 += s15 * 470296;
+  s5 += s15 * 654183;
+  s6 -= s15 * 997805;
+  s7 += s15 * 136657;
+  s8 -= s15 * 683901;
+
+  s2 += s14 * 666643;
+  s3 += s14 * 470296;
+  s4 += s14 * 654183;
+  s5 -= s14 * 997805;
+  s6 += s14 * 136657;
+  s7 -= s14 * 683901;
+
+  s1 += s13 * 666643;
+  s2 += s13 * 470296;
+  s3 += s13 * 654183;
+  s4 -= s13 * 997805;
+  s5 += s13 * 136657;
+  s6 -= s13 * 683901;
+
+  s0 += s12 * 666643; //12 - 0 = 12..
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  //2nd carry
+  carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  //reduce another 21 bits... go from 294 to 273
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  //3rd carry
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  //reduce last 21 bits to go from 273 to get to 2^252..
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+
+  //carry
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  //go from 2^[256/12]'s to 2^[256/32]'s 
+  s[0] = s0 >> 0;
+  s[1] = s0 >> 8;
+  s[2] = (s0 >> 16) | (s1 << 5); // | since there is no overlap
+  s[3] = s1 >> 3;
+  s[4] = s1 >> 11;
+  s[5] = (s1 >> 19) | (s2 << 2);
+  s[6] = s2 >> 6;
+  s[7] = (s2 >> 14) | (s3 << 7);
+  s[8] = s3 >> 1;
+  s[9] = s3 >> 9;
+  s[10] = (s3 >> 17) | (s4 << 4);
+  s[11] = s4 >> 4;
+  s[12] = s4 >> 12;
+  s[13] = (s4 >> 20) | (s5 << 1);
+  s[14] = s5 >> 7;
+  s[15] = (s5 >> 15) | (s6 << 6);
+  s[16] = s6 >> 2;
+  s[17] = s6 >> 10;
+  s[18] = (s6 >> 18) | (s7 << 3);
+  s[19] = s7 >> 5;
+  s[20] = s7 >> 13;
+  s[21] = s8 >> 0;
+  s[22] = s8 >> 8;
+  s[23] = (s8 >> 16) | (s9 << 5);
+  s[24] = s9 >> 3;
+  s[25] = s9 >> 11;
+  s[26] = (s9 >> 19) | (s10 << 2);
+  s[27] = s10 >> 6;
+  s[28] = (s10 >> 14) | (s11 << 7);
+  s[29] = s11 >> 1;
+  s[30] = s11 >> 9;
+  s[31] = s11 >> 17;
+}
+
+/* New code */
+/* (u / v)^(m + 1) */
+static void fe_divpowm1(fe r, const fe u, const fe v) {
+  fe v3, uv7, t0, t1, t2;
+  int i;
+
+  fe_sq(v3, v);
+  fe_mul(v3, v3, v); /* v3 = v^3 */
+  fe_sq(uv7, v3);
+  fe_mul(uv7, uv7, v);
+  fe_mul(uv7, uv7, u); /* uv7 = uv^7 */
+
+  /*fe_pow22523(uv7, uv7);*/
+
+  /* From fe_pow22523.c */
+
+  fe_sq(t0, uv7);
+  fe_sq(t1, t0);
+  fe_sq(t1, t1);
+  fe_mul(t1, uv7, t1);
+  fe_mul(t0, t0, t1);
+  fe_sq(t0, t0);
+  fe_mul(t0, t1, t0);
+  fe_sq(t1, t0);
+  for (i = 0; i < 4; ++i) {
+    fe_sq(t1, t1);
+  }
+  fe_mul(t0, t1, t0);
+  fe_sq(t1, t0);
+  for (i = 0; i < 9; ++i) {
+    fe_sq(t1, t1);
+  }
+  fe_mul(t1, t1, t0);
+  fe_sq(t2, t1);
+  for (i = 0; i < 19; ++i) {
+    fe_sq(t2, t2);
+  }
+  fe_mul(t1, t2, t1);
+  for (i = 0; i < 10; ++i) {
+    fe_sq(t1, t1);
+  }
+  fe_mul(t0, t1, t0);
+  fe_sq(t1, t0);
+  for (i = 0; i < 49; ++i) {
+    fe_sq(t1, t1);
+  }
+  fe_mul(t1, t1, t0);
+  fe_sq(t2, t1);
+  for (i = 0; i < 99; ++i) {
+    fe_sq(t2, t2);
+  }
+  fe_mul(t1, t2, t1);
+  for (i = 0; i < 50; ++i) {
+    fe_sq(t1, t1);
+  }
+  fe_mul(t0, t1, t0);
+  fe_sq(t0, t0);
+  fe_sq(t0, t0);
+  fe_mul(t0, t0, uv7);
+
+  /* End fe_pow22523.c */
+  /* t0 = (uv^7)^((q-5)/8) */
+  fe_mul(t0, t0, v3);
+  fe_mul(r, t0, u); /* u^(m+1)v^(-(m+1)) */
+}
+
+static void ge_cached_0(ge_cached *r) {
+  fe_1(r->YplusX);
+  fe_1(r->YminusX);
+  fe_1(r->Z);
+  fe_0(r->T2d);
+}
+
+static void ge_cached_cmov(ge_cached *t, const ge_cached *u, unsigned char b) {
+  fe_cmov(t->YplusX, u->YplusX, b);
+  fe_cmov(t->YminusX, u->YminusX, b);
+  fe_cmov(t->Z, u->Z, b);
+  fe_cmov(t->T2d, u->T2d, b);
+}
+
+/* Assumes that a[31] <= 127 */
+void ge_scalarmult(ge_p2 *r, const unsigned char *a, const ge_p3 *A) {
+  signed char e[64];
+  int carry, carry2, i;
+  ge_cached Ai[8]; /* 1 * A, 2 * A, ..., 8 * A */
+  ge_p1p1 t;
+  ge_p3 u;
+
+  carry = 0; /* 0..1 */
+  for (i = 0; i < 31; i++) {
+    carry += a[i]; /* 0..256 */
+    carry2 = (carry + 8) >> 4; /* 0..16 */
+    e[2 * i] = carry - (carry2 << 4); /* -8..7 */
+    carry = (carry2 + 8) >> 4; /* 0..1 */
+    e[2 * i + 1] = carry2 - (carry << 4); /* -8..7 */
+  }
+  carry += a[31]; /* 0..128 */
+  carry2 = (carry + 8) >> 4; /* 0..8 */
+  e[62] = carry - (carry2 << 4); /* -8..7 */
+  e[63] = carry2; /* 0..8 */
+
+  ge_p3_to_cached(&Ai[0], A);
+  for (i = 0; i < 7; i++) {
+    ge_add(&t, A, &Ai[i]);
+    ge_p1p1_to_p3(&u, &t);
+    ge_p3_to_cached(&Ai[i + 1], &u);
+  }
+
+  ge_p2_0(r);
+  for (i = 63; i >= 0; i--) {
+    signed char b = e[i];
+    unsigned char bnegative = negative(b);
+    unsigned char babs = b - (((-bnegative) & b) << 1);
+    ge_cached cur, minuscur;
+    ge_p2_dbl(&t, r);
+    ge_p1p1_to_p2(r, &t);
+    ge_p2_dbl(&t, r);
+    ge_p1p1_to_p2(r, &t);
+    ge_p2_dbl(&t, r);
+    ge_p1p1_to_p2(r, &t);
+    ge_p2_dbl(&t, r);
+    ge_p1p1_to_p3(&u, &t);
+    ge_cached_0(&cur);
+    ge_cached_cmov(&cur, &Ai[0], equal(babs, 1));
+    ge_cached_cmov(&cur, &Ai[1], equal(babs, 2));
+    ge_cached_cmov(&cur, &Ai[2], equal(babs, 3));
+    ge_cached_cmov(&cur, &Ai[3], equal(babs, 4));
+    ge_cached_cmov(&cur, &Ai[4], equal(babs, 5));
+    ge_cached_cmov(&cur, &Ai[5], equal(babs, 6));
+    ge_cached_cmov(&cur, &Ai[6], equal(babs, 7));
+    ge_cached_cmov(&cur, &Ai[7], equal(babs, 8));
+    fe_copy(minuscur.YplusX, cur.YminusX);
+    fe_copy(minuscur.YminusX, cur.YplusX);
+    fe_copy(minuscur.Z, cur.Z);
+    fe_neg(minuscur.T2d, cur.T2d);
+    ge_cached_cmov(&cur, &minuscur, bnegative);
+    ge_add(&t, &u, &cur);
+    ge_p1p1_to_p2(r, &t);
+  }
+}
+
+//assume Bi has precomputed multiples
+void ge_double_scalarmult_precomp_vartime(ge_p2 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b, const ge_dsmp Bi) {
+  signed char aslide[256];
+  signed char bslide[256];
+  ge_dsmp Ai; /* A, 3A, 5A, 7A, 9A, 11A, 13A, 15A */ //precomps
+  ge_p1p1 t;
+  ge_p3 u;
+  int i;
+
+  slide(aslide, a);
+  slide(bslide, b);
+  ge_dsm_precomp(Ai, A);
+
+  ge_p2_0(r);
+
+  for (i = 255; i >= 0; --i) {
+    if (aslide[i] || bslide[i]) break;
+  }
+
+  for (; i >= 0; --i) {
+    ge_p2_dbl(&t, r);
+
+    if (aslide[i] > 0) {
+      ge_p1p1_to_p3(&u, &t);
+      ge_add(&t, &u, &Ai[aslide[i]/2]);
+    } else if (aslide[i] < 0) {
+      ge_p1p1_to_p3(&u, &t);
+      ge_sub(&t, &u, &Ai[(-aslide[i])/2]);
+    }
+
+    if (bslide[i] > 0) {
+      ge_p1p1_to_p3(&u, &t);
+      ge_add(&t, &u, &Bi[bslide[i]/2]);
+    } else if (bslide[i] < 0) {
+      ge_p1p1_to_p3(&u, &t);
+      ge_sub(&t, &u, &Bi[(-bslide[i])/2]);
+    }
+
+    ge_p1p1_to_p2(r, &t);
+  }
+}
+
+//x
+void ge_mul8(ge_p1p1 *r, const ge_p2 *t) {
+  ge_p2 u;
+  ge_p2_dbl(r, t);
+  ge_p1p1_to_p2(&u, r);
+  ge_p2_dbl(r, &u);
+  ge_p1p1_to_p2(&u, r);
+  ge_p2_dbl(r, &u);
+}
+
+//x
+void ge_fromfe_frombytes_vartime(ge_p2 *r, const unsigned char *s) {
+  fe u, v, w, x, y, z;
+  unsigned char sign;
+
+  /* From fe_frombytes.c */
+
+  int64_t h0 = load_4(s);
+  int64_t h1 = load_3(s + 4) << 6;
+  int64_t h2 = load_3(s + 7) << 5;
+  int64_t h3 = load_3(s + 10) << 3;
+  int64_t h4 = load_3(s + 13) << 2;
+  int64_t h5 = load_4(s + 16);
+  int64_t h6 = load_3(s + 20) << 7;
+  int64_t h7 = load_3(s + 23) << 5;
+  int64_t h8 = load_3(s + 26) << 4;
+  int64_t h9 = load_3(s + 29) << 2;
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+
+  carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+  carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+  carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+  carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+  carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+  carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+  carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+  carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+  carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+  carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+  u[0] = h0;
+  u[1] = h1;
+  u[2] = h2;
+  u[3] = h3;
+  u[4] = h4;
+  u[5] = h5;
+  u[6] = h6;
+  u[7] = h7;
+  u[8] = h8;
+  u[9] = h9;
+
+  /* End fe_frombytes.c */
+
+  fe_sq2(v, u); /* 2 * u^2 */
+  fe_1(w);
+  fe_add(w, v, w); /* w = 2 * u^2 + 1 */
+  fe_sq(x, w); /* w^2 */
+  fe_mul(y, fe_ma2, v); /* -2 * A^2 * u^2 */
+  fe_add(x, x, y); /* x = w^2 - 2 * A^2 * u^2 */
+  fe_divpowm1(r->X, w, x); /* (w / x)^(m + 1) */
+  fe_sq(y, r->X);
+  fe_mul(x, y, x);
+  fe_sub(y, w, x);
+  fe_copy(z, fe_ma);
+  if (fe_isnonzero(y)) {
+    fe_add(y, w, x);
+    if (fe_isnonzero(y)) {
+      goto negative;
+    } else {
+      fe_mul(r->X, r->X, fe_fffb1);
+    }
+  } else {
+    fe_mul(r->X, r->X, fe_fffb2);
+  }
+  fe_mul(r->X, r->X, u); /* u * sqrt(2 * A * (A + 2) * w / x) */
+  fe_mul(z, z, v); /* -2 * A * u^2 */
+  sign = 0;
+  goto setsign;
+negative:
+  fe_mul(x, x, fe_sqrtm1);
+  fe_sub(y, w, x);
+  if (fe_isnonzero(y)) {
+    assert((fe_add(y, w, x), !fe_isnonzero(y)));
+    fe_mul(r->X, r->X, fe_fffb3);
+  } else {
+    fe_mul(r->X, r->X, fe_fffb4);
+  }
+  /* r->X = sqrt(A * (A + 2) * w / x) */
+  /* z = -A */
+  sign = 1;
+setsign:
+  if (fe_isnegative(r->X) != sign) {
+    assert(fe_isnonzero(r->X));
+    fe_neg(r->X, r->X);
+  }
+  fe_add(r->Z, z, w);
+  fe_sub(r->Y, z, w);
+  fe_mul(r->X, r->X, r->Z);
+#if !defined(NDEBUG)
+  {
+    fe check_x, check_y, check_iz, check_v;
+    fe_invert(check_iz, r->Z);
+    fe_mul(check_x, r->X, check_iz);
+    fe_mul(check_y, r->Y, check_iz);
+    fe_sq(check_x, check_x);
+    fe_sq(check_y, check_y);
+    fe_mul(check_v, check_x, check_y);
+    fe_mul(check_v, fe_d, check_v);
+    fe_add(check_v, check_v, check_x);
+    fe_sub(check_v, check_v, check_y);
+    fe_1(check_x);
+    fe_add(check_v, check_v, check_x);
+    assert(!fe_isnonzero(check_v));
+  }
+#endif
+}
+
+//x
+void sc_0(unsigned char *s) {
+  int i;
+  for (i = 0; i < 32; i++) {
+    s[i] = 0;
+  }
+}
+
+//x
+void sc_reduce32(unsigned char *s) {
+  int64_t s0 = 2097151 & load_3(s);
+  int64_t s1 = 2097151 & (load_4(s + 2) >> 5);
+  int64_t s2 = 2097151 & (load_3(s + 5) >> 2);
+  int64_t s3 = 2097151 & (load_4(s + 7) >> 7);
+  int64_t s4 = 2097151 & (load_4(s + 10) >> 4);
+  int64_t s5 = 2097151 & (load_3(s + 13) >> 1);
+  int64_t s6 = 2097151 & (load_4(s + 15) >> 6);
+  int64_t s7 = 2097151 & (load_3(s + 18) >> 3);
+  int64_t s8 = 2097151 & load_3(s + 21);
+  int64_t s9 = 2097151 & (load_4(s + 23) >> 5);
+  int64_t s10 = 2097151 & (load_3(s + 26) >> 2);
+  int64_t s11 = (load_4(s + 28) >> 7);
+  int64_t s12 = 0;
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+  int64_t carry10;
+  int64_t carry11;
+
+  carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  s[0] = s0 >> 0;
+  s[1] = s0 >> 8;
+  s[2] = (s0 >> 16) | (s1 << 5);
+  s[3] = s1 >> 3;
+  s[4] = s1 >> 11;
+  s[5] = (s1 >> 19) | (s2 << 2);
+  s[6] = s2 >> 6;
+  s[7] = (s2 >> 14) | (s3 << 7);
+  s[8] = s3 >> 1;
+  s[9] = s3 >> 9;
+  s[10] = (s3 >> 17) | (s4 << 4);
+  s[11] = s4 >> 4;
+  s[12] = s4 >> 12;
+  s[13] = (s4 >> 20) | (s5 << 1);
+  s[14] = s5 >> 7;
+  s[15] = (s5 >> 15) | (s6 << 6);
+  s[16] = s6 >> 2;
+  s[17] = s6 >> 10;
+  s[18] = (s6 >> 18) | (s7 << 3);
+  s[19] = s7 >> 5;
+  s[20] = s7 >> 13;
+  s[21] = s8 >> 0;
+  s[22] = s8 >> 8;
+  s[23] = (s8 >> 16) | (s9 << 5);
+  s[24] = s9 >> 3;
+  s[25] = s9 >> 11;
+  s[26] = (s9 >> 19) | (s10 << 2);
+  s[27] = s10 >> 6;
+  s[28] = (s10 >> 14) | (s11 << 7);
+  s[29] = s11 >> 1;
+  s[30] = s11 >> 9;
+  s[31] = s11 >> 17;
+}
+
+//x
+void sc_add(unsigned char *s, const unsigned char *a, const unsigned char *b) {
+  int64_t a0 = 2097151 & load_3(a);
+  int64_t a1 = 2097151 & (load_4(a + 2) >> 5);
+  int64_t a2 = 2097151 & (load_3(a + 5) >> 2);
+  int64_t a3 = 2097151 & (load_4(a + 7) >> 7);
+  int64_t a4 = 2097151 & (load_4(a + 10) >> 4);
+  int64_t a5 = 2097151 & (load_3(a + 13) >> 1);
+  int64_t a6 = 2097151 & (load_4(a + 15) >> 6);
+  int64_t a7 = 2097151 & (load_3(a + 18) >> 3);
+  int64_t a8 = 2097151 & load_3(a + 21);
+  int64_t a9 = 2097151 & (load_4(a + 23) >> 5);
+  int64_t a10 = 2097151 & (load_3(a + 26) >> 2);
+  int64_t a11 = (load_4(a + 28) >> 7);
+  int64_t b0 = 2097151 & load_3(b);
+  int64_t b1 = 2097151 & (load_4(b + 2) >> 5);
+  int64_t b2 = 2097151 & (load_3(b + 5) >> 2);
+  int64_t b3 = 2097151 & (load_4(b + 7) >> 7);
+  int64_t b4 = 2097151 & (load_4(b + 10) >> 4);
+  int64_t b5 = 2097151 & (load_3(b + 13) >> 1);
+  int64_t b6 = 2097151 & (load_4(b + 15) >> 6);
+  int64_t b7 = 2097151 & (load_3(b + 18) >> 3);
+  int64_t b8 = 2097151 & load_3(b + 21);
+  int64_t b9 = 2097151 & (load_4(b + 23) >> 5);
+  int64_t b10 = 2097151 & (load_3(b + 26) >> 2);
+  int64_t b11 = (load_4(b + 28) >> 7);
+  int64_t s0 = a0 + b0;
+  int64_t s1 = a1 + b1;
+  int64_t s2 = a2 + b2;
+  int64_t s3 = a3 + b3;
+  int64_t s4 = a4 + b4;
+  int64_t s5 = a5 + b5;
+  int64_t s6 = a6 + b6;
+  int64_t s7 = a7 + b7;
+  int64_t s8 = a8 + b8;
+  int64_t s9 = a9 + b9;
+  int64_t s10 = a10 + b10;
+  int64_t s11 = a11 + b11;
+  int64_t s12 = 0;
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+  int64_t carry10;
+  int64_t carry11;
+
+  carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  s[0] = s0 >> 0;
+  s[1] = s0 >> 8;
+  s[2] = (s0 >> 16) | (s1 << 5);
+  s[3] = s1 >> 3;
+  s[4] = s1 >> 11;
+  s[5] = (s1 >> 19) | (s2 << 2);
+  s[6] = s2 >> 6;
+  s[7] = (s2 >> 14) | (s3 << 7);
+  s[8] = s3 >> 1;
+  s[9] = s3 >> 9;
+  s[10] = (s3 >> 17) | (s4 << 4);
+  s[11] = s4 >> 4;
+  s[12] = s4 >> 12;
+  s[13] = (s4 >> 20) | (s5 << 1);
+  s[14] = s5 >> 7;
+  s[15] = (s5 >> 15) | (s6 << 6);
+  s[16] = s6 >> 2;
+  s[17] = s6 >> 10;
+  s[18] = (s6 >> 18) | (s7 << 3);
+  s[19] = s7 >> 5;
+  s[20] = s7 >> 13;
+  s[21] = s8 >> 0;
+  s[22] = s8 >> 8;
+  s[23] = (s8 >> 16) | (s9 << 5);
+  s[24] = s9 >> 3;
+  s[25] = s9 >> 11;
+  s[26] = (s9 >> 19) | (s10 << 2);
+  s[27] = s10 >> 6;
+  s[28] = (s10 >> 14) | (s11 << 7);
+  s[29] = s11 >> 1;
+  s[30] = s11 >> 9;
+  s[31] = s11 >> 17;
+}
+
+//x
+void sc_sub(unsigned char *s, const unsigned char *a, const unsigned char *b) {
+  int64_t a0 = 2097151 & load_3(a);
+  int64_t a1 = 2097151 & (load_4(a + 2) >> 5);
+  int64_t a2 = 2097151 & (load_3(a + 5) >> 2);
+  int64_t a3 = 2097151 & (load_4(a + 7) >> 7);
+  int64_t a4 = 2097151 & (load_4(a + 10) >> 4);
+  int64_t a5 = 2097151 & (load_3(a + 13) >> 1);
+  int64_t a6 = 2097151 & (load_4(a + 15) >> 6);
+  int64_t a7 = 2097151 & (load_3(a + 18) >> 3);
+  int64_t a8 = 2097151 & load_3(a + 21);
+  int64_t a9 = 2097151 & (load_4(a + 23) >> 5);
+  int64_t a10 = 2097151 & (load_3(a + 26) >> 2);
+  int64_t a11 = (load_4(a + 28) >> 7);
+  int64_t b0 = 2097151 & load_3(b);
+  int64_t b1 = 2097151 & (load_4(b + 2) >> 5);
+  int64_t b2 = 2097151 & (load_3(b + 5) >> 2);
+  int64_t b3 = 2097151 & (load_4(b + 7) >> 7);
+  int64_t b4 = 2097151 & (load_4(b + 10) >> 4);
+  int64_t b5 = 2097151 & (load_3(b + 13) >> 1);
+  int64_t b6 = 2097151 & (load_4(b + 15) >> 6);
+  int64_t b7 = 2097151 & (load_3(b + 18) >> 3);
+  int64_t b8 = 2097151 & load_3(b + 21);
+  int64_t b9 = 2097151 & (load_4(b + 23) >> 5);
+  int64_t b10 = 2097151 & (load_3(b + 26) >> 2);
+  int64_t b11 = (load_4(b + 28) >> 7);
+  int64_t s0 = a0 - b0;
+  int64_t s1 = a1 - b1;
+  int64_t s2 = a2 - b2;
+  int64_t s3 = a3 - b3;
+  int64_t s4 = a4 - b4;
+  int64_t s5 = a5 - b5;
+  int64_t s6 = a6 - b6;
+  int64_t s7 = a7 - b7;
+  int64_t s8 = a8 - b8;
+  int64_t s9 = a9 - b9;
+  int64_t s10 = a10 - b10;
+  int64_t s11 = a11 - b11;
+  int64_t s12 = 0;
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+  int64_t carry10;
+  int64_t carry11;
+
+  carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  s[0] = s0 >> 0;
+  s[1] = s0 >> 8;
+  s[2] = (s0 >> 16) | (s1 << 5);
+  s[3] = s1 >> 3;
+  s[4] = s1 >> 11;
+  s[5] = (s1 >> 19) | (s2 << 2);
+  s[6] = s2 >> 6;
+  s[7] = (s2 >> 14) | (s3 << 7);
+  s[8] = s3 >> 1;
+  s[9] = s3 >> 9;
+  s[10] = (s3 >> 17) | (s4 << 4);
+  s[11] = s4 >> 4;
+  s[12] = s4 >> 12;
+  s[13] = (s4 >> 20) | (s5 << 1);
+  s[14] = s5 >> 7;
+  s[15] = (s5 >> 15) | (s6 << 6);
+  s[16] = s6 >> 2;
+  s[17] = s6 >> 10;
+  s[18] = (s6 >> 18) | (s7 << 3);
+  s[19] = s7 >> 5;
+  s[20] = s7 >> 13;
+  s[21] = s8 >> 0;
+  s[22] = s8 >> 8;
+  s[23] = (s8 >> 16) | (s9 << 5);
+  s[24] = s9 >> 3;
+  s[25] = s9 >> 11;
+  s[26] = (s9 >> 19) | (s10 << 2);
+  s[27] = s10 >> 6;
+  s[28] = (s10 >> 14) | (s11 << 7);
+  s[29] = s11 >> 1;
+  s[30] = s11 >> 9;
+  s[31] = s11 >> 17;
+}
+
+/*
+Input:
+  a[0]+256*a[1]+...+256^31*a[31] = a
+  b[0]+256*b[1]+...+256^31*b[31] = b
+  c[0]+256*c[1]+...+256^31*c[31] = c
+
+Output:
+  s[0]+256*s[1]+...+256^31*s[31] = (c-ab) mod l
+  where l = 2^252 + 27742317777372353535851937790883648493.
+*/
+
+//x
+void sc_mulsub(unsigned char *s, const unsigned char *a, const unsigned char *b, const unsigned char *c) {
+  int64_t a0 = 2097151 & load_3(a);
+  int64_t a1 = 2097151 & (load_4(a + 2) >> 5);
+  int64_t a2 = 2097151 & (load_3(a + 5) >> 2);
+  int64_t a3 = 2097151 & (load_4(a + 7) >> 7);
+  int64_t a4 = 2097151 & (load_4(a + 10) >> 4);
+  int64_t a5 = 2097151 & (load_3(a + 13) >> 1);
+  int64_t a6 = 2097151 & (load_4(a + 15) >> 6);
+  int64_t a7 = 2097151 & (load_3(a + 18) >> 3);
+  int64_t a8 = 2097151 & load_3(a + 21);
+  int64_t a9 = 2097151 & (load_4(a + 23) >> 5);
+  int64_t a10 = 2097151 & (load_3(a + 26) >> 2);
+  int64_t a11 = (load_4(a + 28) >> 7);
+  int64_t b0 = 2097151 & load_3(b);
+  int64_t b1 = 2097151 & (load_4(b + 2) >> 5);
+  int64_t b2 = 2097151 & (load_3(b + 5) >> 2);
+  int64_t b3 = 2097151 & (load_4(b + 7) >> 7);
+  int64_t b4 = 2097151 & (load_4(b + 10) >> 4);
+  int64_t b5 = 2097151 & (load_3(b + 13) >> 1);
+  int64_t b6 = 2097151 & (load_4(b + 15) >> 6);
+  int64_t b7 = 2097151 & (load_3(b + 18) >> 3);
+  int64_t b8 = 2097151 & load_3(b + 21);
+  int64_t b9 = 2097151 & (load_4(b + 23) >> 5);
+  int64_t b10 = 2097151 & (load_3(b + 26) >> 2);
+  int64_t b11 = (load_4(b + 28) >> 7);
+  int64_t c0 = 2097151 & load_3(c);
+  int64_t c1 = 2097151 & (load_4(c + 2) >> 5);
+  int64_t c2 = 2097151 & (load_3(c + 5) >> 2);
+  int64_t c3 = 2097151 & (load_4(c + 7) >> 7);
+  int64_t c4 = 2097151 & (load_4(c + 10) >> 4);
+  int64_t c5 = 2097151 & (load_3(c + 13) >> 1);
+  int64_t c6 = 2097151 & (load_4(c + 15) >> 6);
+  int64_t c7 = 2097151 & (load_3(c + 18) >> 3);
+  int64_t c8 = 2097151 & load_3(c + 21);
+  int64_t c9 = 2097151 & (load_4(c + 23) >> 5);
+  int64_t c10 = 2097151 & (load_3(c + 26) >> 2);
+  int64_t c11 = (load_4(c + 28) >> 7);
+  int64_t s0;
+  int64_t s1;
+  int64_t s2;
+  int64_t s3;
+  int64_t s4;
+  int64_t s5;
+  int64_t s6;
+  int64_t s7;
+  int64_t s8;
+  int64_t s9;
+  int64_t s10;
+  int64_t s11;
+  int64_t s12;
+  int64_t s13;
+  int64_t s14;
+  int64_t s15;
+  int64_t s16;
+  int64_t s17;
+  int64_t s18;
+  int64_t s19;
+  int64_t s20;
+  int64_t s21;
+  int64_t s22;
+  int64_t s23;
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+  int64_t carry10;
+  int64_t carry11;
+  int64_t carry12;
+  int64_t carry13;
+  int64_t carry14;
+  int64_t carry15;
+  int64_t carry16;
+  int64_t carry17;
+  int64_t carry18;
+  int64_t carry19;
+  int64_t carry20;
+  int64_t carry21;
+  int64_t carry22;
+
+  s0 = c0 - a0*b0;
+  s1 = c1 - (a0*b1 + a1*b0);
+  s2 = c2 - (a0*b2 + a1*b1 + a2*b0);
+  s3 = c3 - (a0*b3 + a1*b2 + a2*b1 + a3*b0);
+  s4 = c4 - (a0*b4 + a1*b3 + a2*b2 + a3*b1 + a4*b0);
+  s5 = c5 - (a0*b5 + a1*b4 + a2*b3 + a3*b2 + a4*b1 + a5*b0);
+  s6 = c6 - (a0*b6 + a1*b5 + a2*b4 + a3*b3 + a4*b2 + a5*b1 + a6*b0);
+  s7 = c7 - (a0*b7 + a1*b6 + a2*b5 + a3*b4 + a4*b3 + a5*b2 + a6*b1 + a7*b0);
+  s8 = c8 - (a0*b8 + a1*b7 + a2*b6 + a3*b5 + a4*b4 + a5*b3 + a6*b2 + a7*b1 + a8*b0);
+  s9 = c9 - (a0*b9 + a1*b8 + a2*b7 + a3*b6 + a4*b5 + a5*b4 + a6*b3 + a7*b2 + a8*b1 + a9*b0);
+  s10 = c10 - (a0*b10 + a1*b9 + a2*b8 + a3*b7 + a4*b6 + a5*b5 + a6*b4 + a7*b3 + a8*b2 + a9*b1 + a10*b0);
+  s11 = c11 - (a0*b11 + a1*b10 + a2*b9 + a3*b8 + a4*b7 + a5*b6 + a6*b5 + a7*b4 + a8*b3 + a9*b2 + a10*b1 + a11*b0);
+  s12 = -(a1*b11 + a2*b10 + a3*b9 + a4*b8 + a5*b7 + a6*b6 + a7*b5 + a8*b4 + a9*b3 + a10*b2 + a11*b1);
+  s13 = -(a2*b11 + a3*b10 + a4*b9 + a5*b8 + a6*b7 + a7*b6 + a8*b5 + a9*b4 + a10*b3 + a11*b2);
+  s14 = -(a3*b11 + a4*b10 + a5*b9 + a6*b8 + a7*b7 + a8*b6 + a9*b5 + a10*b4 + a11*b3);
+  s15 = -(a4*b11 + a5*b10 + a6*b9 + a7*b8 + a8*b7 + a9*b6 + a10*b5 + a11*b4);
+  s16 = -(a5*b11 + a6*b10 + a7*b9 + a8*b8 + a9*b7 + a10*b6 + a11*b5);
+  s17 = -(a6*b11 + a7*b10 + a8*b9 + a9*b8 + a10*b7 + a11*b6);
+  s18 = -(a7*b11 + a8*b10 + a9*b9 + a10*b8 + a11*b7);
+  s19 = -(a8*b11 + a9*b10 + a10*b9 + a11*b8);
+  s20 = -(a9*b11 + a10*b10 + a11*b9);
+  s21 = -(a10*b11 + a11*b10);
+  s22 = -a11*b11;
+  s23 = 0;
+
+  carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
+  carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
+  carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
+  carry18 = (s18 + (1<<20)) >> 21; s19 += carry18; s18 -= carry18 << 21;
+  carry20 = (s20 + (1<<20)) >> 21; s21 += carry20; s20 -= carry20 << 21;
+  carry22 = (s22 + (1<<20)) >> 21; s23 += carry22; s22 -= carry22 << 21;
+
+  carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+  carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
+  carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
+  carry17 = (s17 + (1<<20)) >> 21; s18 += carry17; s17 -= carry17 << 21;
+  carry19 = (s19 + (1<<20)) >> 21; s20 += carry19; s19 -= carry19 << 21;
+  carry21 = (s21 + (1<<20)) >> 21; s22 += carry21; s21 -= carry21 << 21;
+
+  s11 += s23 * 666643;
+  s12 += s23 * 470296;
+  s13 += s23 * 654183;
+  s14 -= s23 * 997805;
+  s15 += s23 * 136657;
+  s16 -= s23 * 683901;
+
+  s10 += s22 * 666643;
+  s11 += s22 * 470296;
+  s12 += s22 * 654183;
+  s13 -= s22 * 997805;
+  s14 += s22 * 136657;
+  s15 -= s22 * 683901;
+
+  s9 += s21 * 666643;
+  s10 += s21 * 470296;
+  s11 += s21 * 654183;
+  s12 -= s21 * 997805;
+  s13 += s21 * 136657;
+  s14 -= s21 * 683901;
+
+  s8 += s20 * 666643;
+  s9 += s20 * 470296;
+  s10 += s20 * 654183;
+  s11 -= s20 * 997805;
+  s12 += s20 * 136657;
+  s13 -= s20 * 683901;
+
+  s7 += s19 * 666643;
+  s8 += s19 * 470296;
+  s9 += s19 * 654183;
+  s10 -= s19 * 997805;
+  s11 += s19 * 136657;
+  s12 -= s19 * 683901;
+
+  s6 += s18 * 666643;
+  s7 += s18 * 470296;
+  s8 += s18 * 654183;
+  s9 -= s18 * 997805;
+  s10 += s18 * 136657;
+  s11 -= s18 * 683901;
+
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
+  carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
+  carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
+
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+  carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
+  carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
+
+  s5 += s17 * 666643;
+  s6 += s17 * 470296;
+  s7 += s17 * 654183;
+  s8 -= s17 * 997805;
+  s9 += s17 * 136657;
+  s10 -= s17 * 683901;
+
+  s4 += s16 * 666643;
+  s5 += s16 * 470296;
+  s6 += s16 * 654183;
+  s7 -= s16 * 997805;
+  s8 += s16 * 136657;
+  s9 -= s16 * 683901;
+
+  s3 += s15 * 666643;
+  s4 += s15 * 470296;
+  s5 += s15 * 654183;
+  s6 -= s15 * 997805;
+  s7 += s15 * 136657;
+  s8 -= s15 * 683901;
+
+  s2 += s14 * 666643;
+  s3 += s14 * 470296;
+  s4 += s14 * 654183;
+  s5 -= s14 * 997805;
+  s6 += s14 * 136657;
+  s7 -= s14 * 683901;
+
+  s1 += s13 * 666643;
+  s2 += s13 * 470296;
+  s3 += s13 * 654183;
+  s4 -= s13 * 997805;
+  s5 += s13 * 136657;
+  s6 -= s13 * 683901;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  s[0] = s0 >> 0;
+  s[1] = s0 >> 8;
+  s[2] = (s0 >> 16) | (s1 << 5);
+  s[3] = s1 >> 3;
+  s[4] = s1 >> 11;
+  s[5] = (s1 >> 19) | (s2 << 2);
+  s[6] = s2 >> 6;
+  s[7] = (s2 >> 14) | (s3 << 7);
+  s[8] = s3 >> 1;
+  s[9] = s3 >> 9;
+  s[10] = (s3 >> 17) | (s4 << 4);
+  s[11] = s4 >> 4;
+  s[12] = s4 >> 12;
+  s[13] = (s4 >> 20) | (s5 << 1);
+  s[14] = s5 >> 7;
+  s[15] = (s5 >> 15) | (s6 << 6);
+  s[16] = s6 >> 2;
+  s[17] = s6 >> 10;
+  s[18] = (s6 >> 18) | (s7 << 3);
+  s[19] = s7 >> 5;
+  s[20] = s7 >> 13;
+  s[21] = s8 >> 0;
+  s[22] = s8 >> 8;
+  s[23] = (s8 >> 16) | (s9 << 5);
+  s[24] = s9 >> 3;
+  s[25] = s9 >> 11;
+  s[26] = (s9 >> 19) | (s10 << 2);
+  s[27] = s10 >> 6;
+  s[28] = (s10 >> 14) | (s11 << 7);
+  s[29] = s11 >> 1;
+  s[30] = s11 >> 9;
+  s[31] = s11 >> 17;
+}
+
+/* Assumes that a != INT64_MIN */
+//x c.f. lt in 32 bit ref
+static int64_t signum(int64_t a) {
+  return (a >> 63) - ((-a) >> 63);
+}
+
+//x
+int sc_check(const unsigned char *s) {
+  int64_t s0 = load_4(s);
+  int64_t s1 = load_4(s + 4);
+  int64_t s2 = load_4(s + 8);
+  int64_t s3 = load_4(s + 12);
+  int64_t s4 = load_4(s + 16);
+  int64_t s5 = load_4(s + 20);
+  int64_t s6 = load_4(s + 24);
+  int64_t s7 = load_4(s + 28);
+  return (signum(1559614444 - s0) + (signum(1477600026 - s1) << 1) + (signum(2734136534 - s2) << 2) + (signum(350157278 - s3) << 3) + (signum(-s4) << 4) + (signum(-s5) << 5) + (signum(-s6) << 6) + (signum(268435456 - s7) << 7)) >> 8;
+}
+
+//x
+int sc_isnonzero(const unsigned char *s) {
+  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;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/crypto-ops.h b/crypt/monero_crypto/crypto_ops_builder/crypto-ops.h
new file mode 100644
index 0000000000..47d5b46aea
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/crypto-ops.h
@@ -0,0 +1,148 @@
+// 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
+#include <stdint.h>
+
+#pragma once
+
+
+/* From fe.h */
+
+//this guy may throw errors in windows
+typedef int32_t fe[10];
+
+/* From ge.h */
+
+typedef struct {
+  fe X;
+  fe Y;
+  fe Z;
+} ge_p2;
+
+typedef struct {
+  fe X;
+  fe Y;
+  fe Z;
+  fe T;
+} ge_p3;
+
+typedef struct {
+  fe X;
+  fe Y;
+  fe Z;
+  fe T;
+} ge_p1p1;
+
+typedef struct {
+  fe yplusx;
+  fe yminusx;
+  fe xy2d;
+} ge_precomp;
+
+typedef struct {
+  fe YplusX;
+  fe YminusX;
+  fe Z;
+  fe T2d;
+} ge_cached;
+
+/* From ge_add.c */
+
+void ge_add(ge_p1p1 *, const ge_p3 *, const ge_cached *);
+
+/* From ge_double_scalarmult.c, modified */
+
+typedef ge_cached ge_dsmp[8];
+extern const ge_precomp ge_Bi[8];
+void ge_dsm_precomp(ge_dsmp r, const ge_p3 *s);
+void ge_double_scalarmult_base_vartime(ge_p2 *, const unsigned char *, const ge_p3 *, const unsigned char *);
+
+/* From ge_frombytes.c, modified */
+
+extern const fe fe_sqrtm1;
+extern const fe fe_d;
+int ge_frombytes_vartime(ge_p3 *, const unsigned char *);
+
+/* From ge_p1p1_to_p2.c */
+
+void ge_p1p1_to_p2(ge_p2 *, const ge_p1p1 *);
+
+/* From ge_p1p1_to_p3.c */
+
+void ge_p1p1_to_p3(ge_p3 *, const ge_p1p1 *);
+
+/* From ge_p2_dbl.c */
+
+void ge_p2_dbl(ge_p1p1 *, const ge_p2 *);
+
+/* From ge_p3_to_cached.c */
+
+extern const fe fe_d2;
+void ge_p3_to_cached(ge_cached *, const ge_p3 *);
+
+/* From ge_p3_to_p2.c */
+
+void ge_p3_to_p2(ge_p2 *, const ge_p3 *);
+
+/* From ge_p3_tobytes.c */
+
+void ge_p3_tobytes(unsigned char *, const ge_p3 *);
+
+/* From ge_scalarmult_base.c */
+
+extern const ge_precomp ge_base[32][8];
+void ge_scalarmult_base(ge_p3 *, const unsigned char *);
+
+/* From ge_tobytes.c */
+
+void ge_tobytes(unsigned char *, const ge_p2 *);
+
+/* From sc_reduce.c */
+
+void sc_reduce(unsigned char *);
+
+/* New code */
+
+void ge_scalarmult(ge_p2 *, const unsigned char *, const ge_p3 *);
+void ge_double_scalarmult_precomp_vartime(ge_p2 *, const unsigned char *, const ge_p3 *, const unsigned char *, const ge_dsmp);
+void ge_mul8(ge_p1p1 *, const ge_p2 *);
+extern const fe fe_ma2;
+extern const fe fe_ma;
+extern const fe fe_fffb1;
+extern const fe fe_fffb2;
+extern const fe fe_fffb3;
+extern const fe fe_fffb4;
+void ge_fromfe_frombytes_vartime(ge_p2 *, const unsigned char *);
+void sc_0(unsigned char *);
+void sc_reduce32(unsigned char *);
+void sc_add(unsigned char *, const unsigned char *, const unsigned char *);
+void sc_sub(unsigned char *, const unsigned char *, const unsigned char *);
+void sc_mulsub(unsigned char *, const unsigned char *, const unsigned char *, const unsigned char *);
+int sc_check(const unsigned char *);
+int sc_isnonzero(const unsigned char *); /* Doesn't normalize */
diff --git a/crypt/monero_crypto/crypto_ops_builder/crypto_int32.h b/crypt/monero_crypto/crypto_ops_builder/crypto_int32.h
new file mode 100755
index 0000000000..cae135e6e2
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/crypto_int32.h
@@ -0,0 +1,6 @@
+#ifndef crypto_int32_h
+#define crypto_int32_h
+
+typedef int crypto_int32;
+
+#endif
diff --git a/crypt/monero_crypto/crypto_ops_builder/crypto_sign.h b/crypt/monero_crypto/crypto_ops_builder/crypto_sign.h
new file mode 100755
index 0000000000..afed20821c
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/crypto_sign.h
@@ -0,0 +1,13 @@
+#ifndef crypto_sign_edwards25519sha512batch_H
+#define crypto_sign_edwards25519sha512batch_H
+
+#define SECRETKEYBYTES 64
+#define PUBLICKEYBYTES 32
+#define SIGNATUREBYTES 64
+
+extern int crypto_sign(unsigned char *,unsigned long long *,const unsigned char *,unsigned long long,const unsigned char *);
+extern int crypto_sign_open(unsigned char *,unsigned long long *,const unsigned char *,unsigned long long,const unsigned char *);
+extern int crypto_sign_keypair(unsigned char *,unsigned char *);
+extern int crypto_sign_publickey(unsigned char *pk, unsigned char *sk, unsigned char *seed);
+
+#endif
diff --git a/crypt/monero_crypto/crypto_ops_builder/crypto_uint32.h b/crypt/monero_crypto/crypto_ops_builder/crypto_uint32.h
new file mode 100755
index 0000000000..21020d7b57
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/crypto_uint32.h
@@ -0,0 +1,6 @@
+#ifndef crypto_uint32_h
+#define crypto_uint32_h
+
+typedef unsigned int crypto_uint32;
+
+#endif
diff --git a/crypt/monero_crypto/crypto_ops_builder/crypto_verify_32.h b/crypt/monero_crypto/crypto_ops_builder/crypto_verify_32.h
new file mode 100755
index 0000000000..ad265c7a3f
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/crypto_verify_32.h
@@ -0,0 +1,7 @@
+#ifndef crypto_verify_32_H
+#define crypto_verify_32_H
+
+#define crypto_verify_32_ref_BYTES 32
+extern int crypto_verify_32(const unsigned char *,const unsigned char *);
+
+#endif
diff --git a/crypt/monero_crypto/crypto_ops_builder/ietf.txt b/crypt/monero_crypto/crypto_ops_builder/ietf.txt
new file mode 100644
index 0000000000..0736f71ec0
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ietf.txt
@@ -0,0 +1,1402 @@
+                                                                        
+
+[Docs] [txt|pdf] [Tracker] [Email] [Diff1] [Diff2] [Nits]               
+                                                                        
+Versions: 00 01 02                                                      
+                                                                        
+Network Working Group                                       S. Josefsson
+Internet-Draft                                                    SJD AB
+Intended status: Informational                                N. Moeller
+Expires: August 26, 2015
+                                                       February 22, 2015
+
+
+                           EdDSA and Ed25519
+
+                    draft-josefsson-eddsa-ed25519-02
+
+
+Abstract
+
+   The elliptic curve signature scheme EdDSA and one instance of it
+   called Ed25519 is described.  An example implementation and test
+   vectors are provided.
+
+Status of This Memo
+
+   This Internet-Draft is submitted in full conformance with the
+   provisions of BCP 78 and BCP 79.
+
+   Internet-Drafts are working documents of the Internet Engineering
+   Task Force (IETF).  Note that other groups may also distribute
+   working documents as Internet-Drafts.  The list of current Internet-
+   Drafts is at http://datatracker.ietf.org/drafts/current/.
+
+   Internet-Drafts are draft documents valid for a maximum of six months
+   and may be updated, replaced, or obsoleted by other documents at any
+   time.  It is inappropriate to use Internet-Drafts as reference
+   material or to cite them other than as "work in progress."
+
+   This Internet-Draft will expire on August 26, 2015.
+
+Copyright Notice
+
+   Copyright (c) 2015 IETF Trust and the persons identified as the
+   document authors.  All rights reserved.
+
+   This document is subject to BCP 78 and the IETF Trust's Legal
+   Provisions Relating to IETF Documents
+   (http://trustee.ietf.org/license-info) in effect on the date of
+   publication of this document.  Please review these documents
+   carefully, as they describe your rights and restrictions with respect
+   to this document.  Code Components extracted from this document must
+   include Simplified BSD License text as described in Section 4.e of
+   the Trust Legal Provisions and are provided without warranty as
+   described in the Simplified BSD License.
+
+
+
+
+Josefsson & Moeller      Expires August 26, 2015                [Page 1]
+
+ 
+Internet-Draft               EdDSA & Ed25519               February 2015
+
+
+Table of Contents
+
+   1.  Introduction  . . . . . . . . . . . . . . . . . . . . . . . .   2
+   2.  Notation  . . . . . . . . . . . . . . . . . . . . . . . . . .   3
+   3.  Background  . . . . . . . . . . . . . . . . . . . . . . . . .   3
+   4.  EdDSA . . . . . . . . . . . . . . . . . . . . . . . . . . . .   4
+     4.1.  Encoding  . . . . . . . . . . . . . . . . . . . . . . . .   4
+     4.2.  Keys  . . . . . . . . . . . . . . . . . . . . . . . . . .   5
+     4.3.  Sign  . . . . . . . . . . . . . . . . . . . . . . . . . .   5
+     4.4.  Verify  . . . . . . . . . . . . . . . . . . . . . . . . .   5
+   5.  Ed25519 . . . . . . . . . . . . . . . . . . . . . . . . . . .   5
+     5.1.  Modular arithmetic  . . . . . . . . . . . . . . . . . . .   6
+     5.2.  Encoding  . . . . . . . . . . . . . . . . . . . . . . . .   6
+     5.3.  Decoding  . . . . . . . . . . . . . . . . . . . . . . . .   6
+     5.4.  Point addition  . . . . . . . . . . . . . . . . . . . . .   7
+     5.5.  Key Generation  . . . . . . . . . . . . . . . . . . . . .   8
+     5.6.  Sign  . . . . . . . . . . . . . . . . . . . . . . . . . .   8
+     5.7.  Verify  . . . . . . . . . . . . . . . . . . . . . . . . .   9
+     5.8.  Python illustration . . . . . . . . . . . . . . . . . . .   9
+   6.  Test Vectors for Ed25519  . . . . . . . . . . . . . . . . . .  14
+   7.  Acknowledgements  . . . . . . . . . . . . . . . . . . . . . .  17
+   8.  IANA Considerations . . . . . . . . . . . . . . . . . . . . .  18
+   9.  Security Considerations . . . . . . . . . . . . . . . . . . .  18
+     9.1.  Side-channel leaks  . . . . . . . . . . . . . . . . . . .  18
+   10. References  . . . . . . . . . . . . . . . . . . . . . . . . .  18
+     10.1.  Normative References . . . . . . . . . . . . . . . . . .  18
+     10.2.  Informative References . . . . . . . . . . . . . . . . .  18
+   Appendix A.  Ed25519 Python Library . . . . . . . . . . . . . . .  19
+   Appendix B.  Library driver . . . . . . . . . . . . . . . . . . .  23
+   Authors' Addresses  . . . . . . . . . . . . . . . . . . . . . . .  24
+
+1.  Introduction
+
+
+   The Edwards-curve Digital Signature Algorithm (EdDSA) is a variant of
+   Schnorr's signature system with Twisted Edwards curves.  EdDSA needs
+   to be instantiated with certain parameters and this document describe
+   Ed25519 - an instantiation of EdDSA in a curve over GF(2^255-19).  To
+   facilitate adoption in the Internet community of Ed25519, this
+   document describe the signature scheme in an implementation-oriented
+   way, and we provide sample code and test vectors.
+
+   The advantages with EdDSA and Ed25519 include:
+
+   1.  High-performance on a variety of platforms.
+
+   2.  Does not require the use of a unique random number for each
+       signature.
+
+
+
+
+Josefsson & Moeller      Expires August 26, 2015                [Page 2]
+
+ 
+Internet-Draft               EdDSA & Ed25519               February 2015
+
+
+   3.  More resilient to side-channel attacks.
+
+   4.  Small public keys (32 bytes) and signatures (64 bytes).
+
+   5.  The formulas are "strongly unified", i.e., they are valid for all
+       points on the curve, with no exceptions.  This obviates the need
+       for EdDSA to perform expensive point validation on untrusted
+       public values.
+
+   6.  Collision resilience, meaning that hash-function collisions do
+       not break this system.
+
+   For further background, see the original EdDSA paper [EDDSA].
+
+2.  Notation
+
+
+   The following notation is used throughout the document:
+
+   GF(p) finite field with p elements
+
+   x^y x multiplied by itself y times
+
+   B generator of the group or subgroup of interest
+
+   n B B added to itself n times.
+
+   h_i the i'th bit of h
+
+   a || b (bit-)string a concatenated with (bit-)string b
+
+3.  Background
+
+
+   EdDSA is defined using an elliptic curve over GF(p) of the form
+
+   -x^2 + y^2 = 1 + d x^2 y^2
+
+   In general, p could be a prime power, but it is usually chosen as a
+   prime number.  It is required that p = 1 modulo 4 (which implies that
+   -1 is a square modulo p) and that d is a non-square modulo p.  For
+   Ed25519, the curve used is equivalent to Curve25519 [CURVE25519],
+   under a change of coordinates, which means that the difficulty of the
+   discrete logarithm problem is the same as for Curve25519.
+
+   Points on this curve form a group under addition, (x3, y3) = (x1, y1)
+   + (x2, y2), with the formulas
+
+
+
+
+
+
+Josefsson & Moeller      Expires August 26, 2015                [Page 3]
+
+ 
+Internet-Draft               EdDSA & Ed25519               February 2015
+
+
+           x1 y2 + x2 y1              y1 y2 + x1 x2
+   x3 = -------------------,  y3 = -------------------
+         1 + d x1 x2 y1 y2          1 - d x1 x2 y1 y2
+
+   The neutral element in the group is (0, 1).
+
+   Unlike manyy other curves used for cryptographic applications, these
+   formulas are "strongly unified": they are valid for all points on the
+   curve, with no exceptions.  In particular, the denominators are non-
+   zero for all input points.
+
+   There are more efficient formulas, which are still strongly unified,
+   which use homogeneous coordinates to avoid the expensive modulo p
+   inversions.  See [Faster-ECC] and [Edwards-revisited].
+
+4.  EdDSA
+
+
+   EdDSA is a digital signature system with several parameters.  The
+   generic EdDSA digital signature system is normally not implemented
+   directly, but instead a particular instance of EdDSA (like Ed25519)
+   is implemented.  A precise explanation of the generic EdDSA is thus
+   not particulary useful for implementers, but for background and
+   completeness, a succint description of the generic EdDSA algorithm is
+   given here.
+
+   EdDSA has seven parameters:
+
+   1.  an integer b >= 10.
+
+   2.  a cryptographic hash function H producing 2b-bit outputs.
+
+   3.  a prime power p congruent to 1 modulo 4.
+
+   4.  a (b-1)-bit encoding of elements of the finite field GF(p).
+
+   5.  a non-square element d of GF(p)
+
+   6.  an element B != (0,1) of the set E = { (x,y) is a member of GF(p)
+       x GF(p) such that -x^2 + y^2 = 1 + dx^2y^2 }.
+
+   7.  a prime q, of size b-3 bits, such that qB = (0, 1), i.e., q is
+       the order of B or a multiple thereof.
+
+4.1.  Encoding
+
+
+   An element (x,y) of E is encoded as a b-bit string called ENC(x,y)
+   which is the (b-1)-bit encoding of y concatenated with one bit that
+   is 1 if x is negative and 0 if x is not negative.  Negative elements
+
+
+
+Josefsson & Moeller      Expires August 26, 2015                [Page 4]
+
+ 
+Internet-Draft               EdDSA & Ed25519               February 2015
+
+
+   of GF(q) are those x which the (b-1)-bit encoding of x is
+   lexicographically larger than the (b-1)-bit encoding of -x.
+
+4.2.  Keys
+
+
+   An EdDSA secret key is a b-bit string k.  Let the hash H(k) = (h_0,
+   h_1, ..., h_(2b-1)) determine an integer a which is 2^(b-2) plus the
+   sum of m = 2^i * h_i for all i equal or larger than 3 and equal to or
+   less than b-3 such that m is a member of the set { 2^(b-2), 2^(b-2) +
+   8, ..., 2^(b-1) - 8 }.  The EdDSA public key is ENC(A) = ENC(aB).
+   The bits h_b, ..., h_(2b-1) is used below during signing.
+
+4.3.  Sign
+
+
+   The signature of a message M under a secret key k is the 2b-bit
+   string ENC(R) || ENC'(S), where ENC'(S) is defined as the b-bit
+   little-endian encoding of S.  R and S are derived as follows.  First
+   define r = H(h_b, ... h_(2b-1)), M) interpreting 2b-bit strings in
+   little-endian form as integers in {0, 1, ..., 2^(2b)-1}.  Let R=rB
+   and S=(r+H(ENC(R) || ENC(A) || M)a) mod l.
+
+4.4.  Verify
+
+
+   To verify a signature ENC(R) || ENC'(S) on a message M under a public
+   key ENC(A), proceed as follows.  Parse the inputs so that A and R is
+   an element of E, and S is a member of the set {0, 1, ..., l-1 }.
+   Compute H' = H(ENC(R) || ENC(A) || M) and check the group equation
+   8SB = 8R + 8H'A in E.  Verification is rejected if parsing fails or
+   the group equation does not hold.
+
+5.  Ed25519
+
+
+   Theoretically, Ed25519 is EdDSA instantiated with b=256, H being
+   SHA-512 [RFC4634], p is the prime 2^255-19, the 255-bit encoding of
+   GF(2^255-19) being the little-endian encoding of {0, 1, ...,
+   2^255-20}, q is the prime 2^252 + 0x14def9dea2f79cd65812631a5cf5d3ed,
+   d = -121665/121666 which is a member of GF(p), and B is the unique
+   point (x, 4/5) in E for which x is "positive", which with the
+   encoding used simply means that the least significant bit of x is 0.
+   The curve p, prime q, d and B follows from [I-D.irtf-cfrg-curves].
+
+   Written out explicitly, B is the point (15112221349535400772501151409
+   588531511454012693041857206046113283949847762202, 4631683569492647816
+   9428394003475163141307993866256225615783033603165251855960).
+
+
+
+
+
+
+
+Josefsson & Moeller      Expires August 26, 2015                [Page 5]
+
+ 
+Internet-Draft               EdDSA & Ed25519               February 2015
+
+
+5.1.  Modular arithmetic
+
+
+   For advise on how to implement arithmetic modulo p = 2^255 - 1
+   efficiently and securely, see Curve25519 [CURVE25519].  For inversion
+   modulo p, it is recommended to use the identity x^-1 = x^(p-2) (mod
+   p).
+
+   For point decoding or "decompression", square roots modulo p are
+   needed.  They can be computed using the Tonelli-Shanks algorithm, or
+   the special case for p = 5 (mod 8).  To find a square root of a,
+   first compute the candidate root x = a^((p+3)/8) (mod p).  Then there
+   are three cases:
+
+      x^2 = a (mod p).  Then x is a square root.
+
+      x^2 = -a (mod p).  Then 2^((p-1)/4) x is a square root.
+
+      a is not a square modulo p.
+
+5.2.  Encoding
+
+
+   All values are coded as octet strings, and integers are coded using
+   little endian convention.  I.e., a 32-octet string h h[0],...h[31]
+   represents the integer h[0] + 2^8 h[1] + ... + 2^248 h[31].
+
+   A curve point (x,y), with coordiantes in the range 0 <= x,y < p, is
+   coded as follows.  First encode the y-coordinate as a little-endian
+   string of 32 octets.  The most significant bit of the final octet is
+   always zero.  To form the encoding of the point, copy the least
+   significant bit of the x-coordinate to the most significant bit of
+   the final octet.
+
+5.3.  Decoding
+
+
+   Decoding a point, given as a 32-octet string, is a little more
+   complicated.
+
+   1.  First interpret the string as an integer in little-endian
+       representation.  Bit 255 of this number is the least significant
+       bit of the x-coordinate, and denote this value x_0.  The
+       y-coordinate is recovered simply by clearing this bit.  If the
+       resulting value is >= p, decoding fails.
+
+   2.  To recover the x coordinate, the curve equation implies x^2 =
+       (y^2 - 1) / (d y^2 + 1) (mod p).  Since d is a non-square and -1
+       is a square, the numerator, (d y^2 + 1), is always invertible
+       modulo p.  Let u = y^2 - 1 and v = d y^2 + 1.  To compute the
+       square root of (u/v), the first step is to compute the candidate
+
+
+
+Josefsson & Moeller      Expires August 26, 2015                [Page 6]
+
+ 
+Internet-Draft               EdDSA & Ed25519               February 2015
+
+
+       root x = (u/v)^((p+3)/8).  This can be done using the following
+       trick, to use a single modular powering for both the inversion of
+       v and the square root:
+
+                      (p+3)/8      3        (p-5)/8
+             x = (u/v)        = u v  (u v^7)         (mod p)
+
+   3.  Again, there are three cases:
+
+       1.  If v x^2 = u (mod p), x is a square root.
+
+       2.  If v x^2 = -u (mod p), set x <-- x 2^((p-1)/4), which is a
+           square root.
+
+       3.  Otherwise, no square root exists modulo p, and decoding
+           fails.
+
+   4.  Finally, use the x_0 bit to select the right square root.  If x =
+       0, and x_0 = 1, decoding fails.  Otherwise, if x_0 != x mod 2,
+       set x <-- p - x.  Return the decoded point (x,y).
+
+5.4.  Point addition
+
+
+   For point addition, the following method is recommended.  A point
+   (x,y) is represented in extended homogeneous coordinates (X, Y, Z,
+   T), with x = X/Z, y = Y/Z, x y = T/Z.
+
+   The following formulas for adding two points, (x3,y3) =
+   (x1,y1)+(x2,y2) are described in [Edwards-revisited], section 3.1.
+   They are strongly unified, i.e., they work for any pair of valid
+   input points.
+
+           A = (Y1-X1)*(Y2-X2)
+           B = (Y1+X1)*(Y2+X2)
+           C = T1*2*d*T2
+           D = Z1*2*Z2
+           E = B-A
+           F = D-C
+           G = D+C
+           H = B+A
+           X3 = E*F
+           Y3 = G*H
+           T3 = E*H
+           Z3 = F*G
+
+
+
+
+
+
+
+Josefsson & Moeller      Expires August 26, 2015                [Page 7]
+
+ 
+Internet-Draft               EdDSA & Ed25519               February 2015
+
+
+5.5.  Key Generation
+
+
+   The secret is 32 octets (256 bits, corresponding to b) of
+   cryptographically-secure random data.  See [RFC4086] for a discussion
+   about randomness.
+
+   The 32-byte public key is generated by the following steps.
+
+   1.  Hash the 32-byte secret using SHA-512, storing the digest in a
+       64-octet large buffer, denoted h.  Only the lower 32 bytes are
+       used for generating the public key.
+
+   2.  Prune the buffer.  In C terminology:
+
+             h[0] &= ~0x07;
+             h[31] &= 0x7F;
+             h[31] |= 0x40;
+
+   3.  Interpret the buffer as the little-endian integer, forming a
+       secret scalar a.  Perform a known-base-point scalar
+       multiplication a B.
+
+   4.  The public key A is the encoding of the point aB.  First encode
+       the y coordinate (in the range 0 <= y < p) as a little-endian
+       string of 32 octets.  The most significant bit of the final octet
+       is always zero.  To form the encoding of the point aB, copy the
+       least significant bit of the x coordinate to the most significant
+       bit of the final octet.  The result is the public key.
+
+5.6.  Sign
+
+
+   The imputs to the signing procedure is the secret key, a 32-octet
+   string, and a message M of arbitrary size.
+
+   1.  Hash the secret key, 32-octets, using SHA-512.  Let h denote the
+       resulting digest.  Construct the secret scalar a from the first
+       half of the digest, and the corresponding public key A, as
+       described in the previous section.  Let prefix denote the second
+       half of the hash digest, h[32],...,h[63].
+
+   2.  Compute SHA-512(prefix || M), where M is the message to be
+       signed.  Interpret the 64-octet digest as a little-endian integer
+       r.
+
+   3.  Compute the point rB.  For efficiency, do this by first reducing
+       r modulo q, the group order of B.  Let the string R be the
+       encoding of this point.
+
+
+
+
+Josefsson & Moeller      Expires August 26, 2015                [Page 8]
+
+ 
+Internet-Draft               EdDSA & Ed25519               February 2015
+
+
+   4.  Compute SHA512(R || A || M), and interpret the 64-octet digest as
+       a little-endian integer k.
+
+   5.  Compute s = (r + k a) mod q.  For efficiency, again reduce k
+       modulo q first.
+
+   6.  Form the signature of the concatenation of R (32 octets) and the
+       little-endian encoding of s (32 octets, three most significant
+       bits of the final octets always zero).
+
+5.7.  Verify
+
+
+   1.  To verify a signature on a message M, first split the signature
+       into two 32-octet halves.  Decode the first half as a point R,
+       and the second half as an integer s, in the range 0 <= s < q.  If
+       the decoding fails, the signature is invalid.
+
+   2.  Compute SHA512(R || A || M), and interpret the 64-octet digest as
+       a little-endian integer k.
+
+   3.  Check the group equation 8s B = 8 R + 8k A.  It's sufficient, but
+       not required, to instead check s B = R + k A.
+
+5.8.  Python illustration
+
+
+   The rest of this section describes how Ed25519 can be implemented in
+   Python (version 3.2 or later) for illustration.  See appendix A for
+   the complete implementation and appendix B for a test-driver to run
+   it through some test vectors.
+
+   First some preliminaries that will be needed.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Josefsson & Moeller      Expires August 26, 2015                [Page 9]
+
+ 
+Internet-Draft               EdDSA & Ed25519               February 2015
+
+
+   import hashlib
+
+   def sha512(s):
+       return hashlib.sha512(s).digest()
+
+   # Base field Z_p
+   p = 2**255 - 19
+
+   def modp_inv(x):
+       return pow(x, p-2, p)
+
+   # Curve constant
+   d = -121665 * modp_inv(121666) % p
+
+   # Group order
+   q = 2**252 + 27742317777372353535851937790883648493
+
+   def sha512_modq(s):
+       return int.from_bytes(sha512(s), "little") % q
+
+   Then follows functions to perform point operations.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Josefsson & Moeller      Expires August 26, 2015               [Page 10]
+
+ 
+Internet-Draft               EdDSA & Ed25519               February 2015
+
+
+# Points are represented as tuples (X, Y, Z, T) of extended coordinates,
+# with x = X/Z, y = Y/Z, x*y = T/Z
+
+def point_add(P, Q):
+    A = (P[1]-P[0])*(Q[1]-Q[0]) % p
+    B = (P[1]+P[0])*(Q[1]+Q[0]) % p
+    C = 2 * P[3] * Q[3] * d % p
+    D = 2 * P[2] * Q[2] % p
+    E = B-A
+    F = D-C
+    G = D+C
+    H = B+A
+    return (E*F, G*H, F*G, E*H)
+
+# Computes Q = s * Q
+def point_mul(s, P):
+    Q = (0, 1, 1, 0)  # Neutral element
+    while s > 0:
+        # Is there any bit-set predicate?
+        if s & 1:
+            Q = point_add(Q, P)
+        P = point_add(P, P)
+        s >>= 1
+    return Q
+
+def point_equal(P, Q):
+    # x1 / z1 == x2 / z2  <==>  x1 * z2 == x2 * z1
+    if (P[0] * Q[2] - Q[0] * P[2]) % p != 0:
+        return False
+    if (P[1] * Q[2] - Q[1] * P[2]) % p != 0:
+        return False
+    return True
+
+   Now follows functions for point compression.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Josefsson & Moeller      Expires August 26, 2015               [Page 11]
+
+ 
+Internet-Draft               EdDSA & Ed25519               February 2015
+
+
+# Square root of -1
+modp_sqrt_m1 = pow(2, (p-1) // 4, p)
+
+# Compute corresponding x coordinate, with low bit corresponding to sign,
+# or return None on failure
+def recover_x(y, sign):
+    x2 = (y*y-1) * modp_inv(d*y*y+1)
+    if x2 == 0:
+        if sign:
+            return None
+        else:
+            return 0
+
+    # Compute square root of x2
+    x = pow(x2, (p+3) // 8, p)
+    if (x*x - x2) % p != 0:
+        x = x * modp_sqrt_m1 % p
+    if (x*x - x2) % p != 0:
+        return None
+
+    if (x & 1) != sign:
+        x = p - x
+    return x
+
+# Base point
+g_y = 4 * modp_inv(5) % p
+g_x = recover_x(g_y, 0)
+G = (g_x, g_y, 1, g_x * g_y % p)
+
+def point_compress(P):
+    zinv = modp_inv(P[2])
+    x = P[0] * zinv % p
+    y = P[1] * zinv % p
+    return int.to_bytes(y | ((x & 1) << 255), 32, "little")
+
+def point_decompress(s):
+    if len(s) != 32:
+        raise Exception("Invalid input length for decompression")
+    y = int.from_bytes(s, "little")
+    sign = y >> 255
+    y &= (1 << 255) - 1
+
+    x = recover_x(y, sign)
+    if x is None:
+        return None
+    else:
+        return (x, y, 1, x*y % p)
+
+
+
+
+Josefsson & Moeller      Expires August 26, 2015               [Page 12]
+
+ 
+Internet-Draft               EdDSA & Ed25519               February 2015
+
+
+   These are functions for manipulating the secret.
+
+   def secret_expand(secret):
+       if len(secret) != 32:
+           raise Exception("Bad size of private key")
+       h = sha512(secret)
+       a = int.from_bytes(h[:32], "little")
+       a &= (1 << 254) - 8
+       a |= (1 << 254)
+       return (a, h[32:])
+
+   def secret_to_public(secret):
+       (a, dummy) = secret_expand(secret)
+       return point_compress(point_mul(a, G))
+
+   The signature function works as below.
+
+   def sign(secret, msg):
+       a, prefix = secret_expand(secret)
+       A = point_compress(point_mul(a, G))
+       r = sha512_modq(prefix + msg)
+       R = point_mul(r, G)
+       Rs = point_compress(R)
+       h = sha512_modq(Rs + A + msg)
+       s = (r + h * a) % q
+       return Rs + int.to_bytes(s, 32, "little")
+
+   And finally the verification function.
+
+   def verify(public, msg, signature):
+       if len(public) != 32:
+           raise Exception("Bad public-key length")
+       if len(signature) != 64:
+           Exception("Bad signature length")
+       A = point_decompress(public)
+       if not A:
+           return False
+       Rs = signature[:32]
+       R = point_decompress(Rs)
+       if not R:
+           return False
+       s = int.from_bytes(signature[32:], "little")
+       h = sha512_modq(Rs + public + msg)
+       sB = point_mul(s, G)
+       hA = point_mul(h, A)
+       return point_equal(sB, point_add(R, hA))
+
+
+
+
+
+Josefsson & Moeller      Expires August 26, 2015               [Page 13]
+
+ 
+Internet-Draft               EdDSA & Ed25519               February 2015
+
+
+6.  Test Vectors for Ed25519
+
+
+   Below is a sequence of octets with test vectors for the the Ed25519
+   signature algorithm.  The octets are hex encoded and whitespace is
+   inserted for readability.  Private keys are 64 bytes, public keys 32
+   bytes, message of arbitrary length, and signatures are 64 bytes.  The
+   test vectors are taken from [ED25519-TEST-VECTORS] (but we removed
+   the public key as a suffix of the secret key, and removed the message
+   from the signature) and [ED25519-LIBGCRYPT-TEST-VECTORS].
+
+   -----TEST 1
+   SECRET KEY:
+   9d61b19deffd5a60ba844af492ec2cc4
+   4449c5697b326919703bac031cae7f60
+
+   PUBLIC KEY:
+   d75a980182b10ab7d54bfed3c964073a
+   0ee172f3daa62325af021a68f707511a
+
+   MESSAGE (length 0 bytes):
+
+   SIGNATURE:
+   e5564300c360ac729086e2cc806e828a
+   84877f1eb8e5d974d873e06522490155
+   5fb8821590a33bacc61e39701cf9b46b
+   d25bf5f0595bbe24655141438e7a100b
+
+   -----TEST 2
+   SECRET KEY:
+   4ccd089b28ff96da9db6c346ec114e0f
+   5b8a319f35aba624da8cf6ed4fb8a6fb
+
+   PUBLIC KEY:
+   3d4017c3e843895a92b70aa74d1b7ebc
+   9c982ccf2ec4968cc0cd55f12af4660c
+
+   MESSAGE (length 1 byte):
+   72
+
+   SIGNATURE:
+   92a009a9f0d4cab8720e820b5f642540
+   a2b27b5416503f8fb3762223ebdb69da
+   085ac1e43e15996e458f3613d0f11d8c
+   387b2eaeb4302aeeb00d291612bb0c00
+
+   -----TEST 3
+   SECRET KEY:
+   c5aa8df43f9f837bedb7442f31dcb7b1
+
+
+
+Josefsson & Moeller      Expires August 26, 2015               [Page 14]
+
+ 
+Internet-Draft               EdDSA & Ed25519               February 2015
+
+
+   66d38535076f094b85ce3a2e0b4458f7
+
+   PUBLIC KEY:
+   fc51cd8e6218a1a38da47ed00230f058
+   0816ed13ba3303ac5deb911548908025
+
+   MESSAGE (length 2 bytes):
+   af82
+
+   SIGNATURE:
+   6291d657deec24024827e69c3abe01a3
+   0ce548a284743a445e3680d7db5ac3ac
+   18ff9b538d16f290ae67f760984dc659
+   4a7c15e9716ed28dc027beceea1ec40a
+
+   -----TEST 1024
+   SECRET KEY:
+   f5e5767cf153319517630f226876b86c
+   8160cc583bc013744c6bf255f5cc0ee5
+
+   PUBLIC KEY:
+   278117fc144c72340f67d0f2316e8386
+   ceffbf2b2428c9c51fef7c597f1d426e
+
+   MESSAGE:
+   08b8b2b733424243760fe426a4b54908
+   632110a66c2f6591eabd3345e3e4eb98
+   fa6e264bf09efe12ee50f8f54e9f77b1
+   e355f6c50544e23fb1433ddf73be84d8
+   79de7c0046dc4996d9e773f4bc9efe57
+   38829adb26c81b37c93a1b270b20329d
+   658675fc6ea534e0810a4432826bf58c
+   941efb65d57a338bbd2e26640f89ffbc
+   1a858efcb8550ee3a5e1998bd177e93a
+   7363c344fe6b199ee5d02e82d522c4fe
+   ba15452f80288a821a579116ec6dad2b
+   3b310da903401aa62100ab5d1a36553e
+   06203b33890cc9b832f79ef80560ccb9
+   a39ce767967ed628c6ad573cb116dbef
+   efd75499da96bd68a8a97b928a8bbc10
+   3b6621fcde2beca1231d206be6cd9ec7
+   aff6f6c94fcd7204ed3455c68c83f4a4
+   1da4af2b74ef5c53f1d8ac70bdcb7ed1
+   85ce81bd84359d44254d95629e9855a9
+   4a7c1958d1f8ada5d0532ed8a5aa3fb2
+   d17ba70eb6248e594e1a2297acbbb39d
+   502f1a8c6eb6f1ce22b3de1a1f40cc24
+   554119a831a9aad6079cad88425de6bd
+
+
+
+Josefsson & Moeller      Expires August 26, 2015               [Page 15]
+
+ 
+Internet-Draft               EdDSA & Ed25519               February 2015
+
+
+   e1a9187ebb6092cf67bf2b13fd65f270
+   88d78b7e883c8759d2c4f5c65adb7553
+   878ad575f9fad878e80a0c9ba63bcbcc
+   2732e69485bbc9c90bfbd62481d9089b
+   eccf80cfe2df16a2cf65bd92dd597b07
+   07e0917af48bbb75fed413d238f5555a
+   7a569d80c3414a8d0859dc65a46128ba
+   b27af87a71314f318c782b23ebfe808b
+   82b0ce26401d2e22f04d83d1255dc51a
+   ddd3b75a2b1ae0784504df543af8969b
+   e3ea7082ff7fc9888c144da2af58429e
+   c96031dbcad3dad9af0dcbaaaf268cb8
+   fcffead94f3c7ca495e056a9b47acdb7
+   51fb73e666c6c655ade8297297d07ad1
+   ba5e43f1bca32301651339e22904cc8c
+   42f58c30c04aafdb038dda0847dd988d
+   cda6f3bfd15c4b4c4525004aa06eeff8
+   ca61783aacec57fb3d1f92b0fe2fd1a8
+   5f6724517b65e614ad6808d6f6ee34df
+   f7310fdc82aebfd904b01e1dc54b2927
+   094b2db68d6f903b68401adebf5a7e08
+   d78ff4ef5d63653a65040cf9bfd4aca7
+   984a74d37145986780fc0b16ac451649
+   de6188a7dbdf191f64b5fc5e2ab47b57
+   f7f7276cd419c17a3ca8e1b939ae49e4
+   88acba6b965610b5480109c8b17b80e1
+   b7b750dfc7598d5d5011fd2dcc5600a3
+   2ef5b52a1ecc820e308aa342721aac09
+   43bf6686b64b2579376504ccc493d97e
+   6aed3fb0f9cd71a43dd497f01f17c0e2
+   cb3797aa2a2f256656168e6c496afc5f
+   b93246f6b1116398a346f1a641f3b041
+   e989f7914f90cc2c7fff357876e506b5
+   0d334ba77c225bc307ba537152f3f161
+   0e4eafe595f6d9d90d11faa933a15ef1
+   369546868a7f3a45a96768d40fd9d034
+   12c091c6315cf4fde7cb68606937380d
+   b2eaaa707b4c4185c32eddcdd306705e
+   4dc1ffc872eeee475a64dfac86aba41c
+   0618983f8741c5ef68d3a101e8a3b8ca
+   c60c905c15fc910840b94c00a0b9d0
+
+   SIGNATURE:
+   0aab4c900501b3e24d7cdf4663326a3a
+   87df5e4843b2cbdb67cbf6e460fec350
+   aa5371b1508f9f4528ecea23c436d94b
+   5e8fcd4f681e30a6ac00a9704a188a03
+
+
+
+
+Josefsson & Moeller      Expires August 26, 2015               [Page 16]
+
+ 
+Internet-Draft               EdDSA & Ed25519               February 2015
+
+
+   -----TEST 1A
+   -----An additional test with the data from test 1 but using an
+   -----uncompressed public key.
+   SECRET KEY:
+   9d61b19deffd5a60ba844af492ec2cc4
+   4449c5697b326919703bac031cae7f60
+
+   PUBLIC KEY:
+   0455d0e09a2b9d34292297e08d60d0f6
+   20c513d47253187c24b12786bd777645
+   ce1a5107f7681a02af2523a6daf372e1
+   0e3a0764c9d3fe4bd5b70ab18201985a
+   d7
+
+   MSG (length 0 bytes):
+
+   SIGNATURE:
+   e5564300c360ac729086e2cc806e828a
+   84877f1eb8e5d974d873e06522490155
+   5fb8821590a33bacc61e39701cf9b46b
+   d25bf5f0595bbe24655141438e7a100b
+
+   -----TEST 1B
+   -----An additional test with the data from test 1 but using an
+   -----compressed prefix.
+   SECRET KEY:
+   9d61b19deffd5a60ba844af492ec2cc4
+   4449c5697b326919703bac031cae7f60
+
+   PUBLIC KEY:
+   40d75a980182b10ab7d54bfed3c96407
+   3a0ee172f3daa62325af021a68f70751
+   1a
+
+   MESSAGE (length 0 bytes):
+
+   SIGNATURE:
+   e5564300c360ac729086e2cc806e828a
+   84877f1eb8e5d974d873e06522490155
+   5fb8821590a33bacc61e39701cf9b46b
+   d25bf5f0595bbe24655141438e7a100b
+   -----
+
+7.  Acknowledgements
+
+
+   Feedback on this document was received from Werner Koch and Damien
+   Miller.
+
+
+
+
+Josefsson & Moeller      Expires August 26, 2015               [Page 17]
+
+ 
+Internet-Draft               EdDSA & Ed25519               February 2015
+
+
+8.  IANA Considerations
+
+
+   None.
+
+9.  Security Considerations
+
+
+9.1.  Side-channel leaks
+
+
+   For implementations performing signatures, secrecy of the key is
+   fundamental.  It is possible to protect against some side-channel
+   attacks by ensuring that the implementation executes exactly the same
+   sequence of instructions and performs exactly the same memory
+   accesses, for any value of the secret key.
+
+   To make an implementation side-channel silent in this way, the modulo
+   p arithmetic must not use any data-dependent branches, e.g., related
+   to carry propagation.  Side channel-silent point addition is
+   straight-forward, thanks to the unified formulas.
+
+   Scalar multiplication, multiplying a point by an integer, needs some
+   additional effort to implement in a side-channel silent manner.  One
+   simple approach is to implement a side-channel silent conditional
+   assignment, and use together with the binary algorithm to examine one
+   bit of the integer at a time.
+
+   Note that the example implementation in this document does not
+   attempt to be side-channel silent.
+
+10.  References
+
+
+10.1.  Normative References
+
+
+   [RFC4634]  Eastlake, D. and T. Hansen, "US Secure Hash Algorithms
+              (SHA and HMAC-SHA)", RFC 4634, July 2006.
+
+   [I-D.irtf-cfrg-curves]
+              Langley, A., Salz, R., and S. Turner, "Elliptic Curves for
+              Security", draft-irtf-cfrg-curves-01 (work in progress),
+              January 2015.
+
+10.2.  Informative References
+
+
+   [RFC4086]  Eastlake, D., Schiller, J., and S. Crocker, "Randomness
+              Requirements for Security", BCP 106, RFC 4086, June 2005.
+
+
+
+
+
+
+
+Josefsson & Moeller      Expires August 26, 2015               [Page 18]
+
+ 
+Internet-Draft               EdDSA & Ed25519               February 2015
+
+
+   [EDDSA]    Bernstein, D., Duif, N., Lange, T., Schwabe, P., and B.
+              Yang, "High-speed high-security signatures", WWW
+              http://ed25519.cr.yp.to/ed25519-20110926.pdf, September
+              2011.
+
+   [Faster-ECC]
+              Bernstein, D. and T. Lange, "Faster addition and doubling
+              on elliptic curves", WWW http://eprint.iacr.org/2007/286,
+              July 2007.
+
+   [Edwards-revisited]
+              Hisil, H., Wong, K., Carter, G., and E. Dawson, "Twisted
+              Edwards Curves Revisited", WWW
+              http://eprint.iacr.org/2008/522, December 2008.
+
+   [CURVE25519]
+              Bernstein, D., "Curve25519: new Diffie-Hellman speed
+              records", WWW http://cr.yp.to/ecdh.html, February 2006.
+
+   [ED25519-TEST-VECTORS]
+              Bernstein, D., Duif, N., Lange, T., Schwabe, P., and B.
+              Yang, "Ed25519 test vectors", WWW
+              http://ed25519.cr.yp.to/python/sign.input, July 2011.
+
+   [ED25519-LIBGCRYPT-TEST-VECTORS]
+              Koch, W., "Ed25519 Libgcrypt test vectors", WWW
+              http://git.gnupg.org/cgi-
+              bin/gitweb.cgi?p=libgcrypt.git;a=blob;f=tests/t-ed25519.in
+              p;h=e13566f826321eece65e02c593bc7d885b3dbe23;hb=refs/
+              heads/master, July 2014.
+
+Appendix A.  Ed25519 Python Library
+
+
+   Below is an example implementation of Ed25519 written in Python,
+   version 3.2 or higher is required.
+
+# Loosely based on the public domain code at
+# http://ed25519.cr.yp.to/software.html
+#
+# Needs python-3.2
+
+import hashlib
+
+
+def sha512(s):
+    return hashlib.sha512(s).digest()
+
+# Base field Z_p
+
+
+
+Josefsson & Moeller      Expires August 26, 2015               [Page 19]
+
+ 
+Internet-Draft               EdDSA & Ed25519               February 2015
+
+
+p = 2**255 - 19
+
+
+def modp_inv(x):
+    return pow(x, p-2, p)
+
+# Curve constant
+d = -121665 * modp_inv(121666) % p
+
+# Group order
+q = 2**252 + 27742317777372353535851937790883648493
+
+
+def sha512_modq(s):
+    return int.from_bytes(sha512(s), "little") % q
+
+# Points are represented as tuples (X, Y, Z, T) of extended coordinates,
+# with x = X/Z, y = Y/Z, x*y = T/Z
+
+
+def point_add(P, Q):
+    A = (P[1]-P[0])*(Q[1]-Q[0]) % p
+    B = (P[1]+P[0])*(Q[1]+Q[0]) % p
+    C = 2 * P[3] * Q[3] * d % p
+    D = 2 * P[2] * Q[2] % p
+    E = B-A
+    F = D-C
+    G = D+C
+    H = B+A
+    return (E*F, G*H, F*G, E*H)
+
+
+# Computes Q = s * Q
+def point_mul(s, P):
+    Q = (0, 1, 1, 0)  # Neutral element
+    while s > 0:
+        # Is there any bit-set predicate?
+        if s & 1:
+            Q = point_add(Q, P)
+        P = point_add(P, P)
+        s >>= 1
+    return Q
+
+
+def point_equal(P, Q):
+    # x1 / z1 == x2 / z2  <==>  x1 * z2 == x2 * z1
+    if (P[0] * Q[2] - Q[0] * P[2]) % p != 0:
+        return False
+
+
+
+Josefsson & Moeller      Expires August 26, 2015               [Page 20]
+
+ 
+Internet-Draft               EdDSA & Ed25519               February 2015
+
+
+    if (P[1] * Q[2] - Q[1] * P[2]) % p != 0:
+        return False
+    return True
+
+# Square root of -1
+modp_sqrt_m1 = pow(2, (p-1) // 4, p)
+
+
+# Compute corresponding x coordinate, with low bit corresponding to sign,
+# or return None on failure
+def recover_x(y, sign):
+    x2 = (y*y-1) * modp_inv(d*y*y+1)
+    if x2 == 0:
+        if sign:
+            return None
+        else:
+            return 0
+
+    # Compute square root of x2
+    x = pow(x2, (p+3) // 8, p)
+    if (x*x - x2) % p != 0:
+        x = x * modp_sqrt_m1 % p
+    if (x*x - x2) % p != 0:
+        return None
+
+    if (x & 1) != sign:
+        x = p - x
+    return x
+
+# Base point
+g_y = 4 * modp_inv(5) % p
+g_x = recover_x(g_y, 0)
+G = (g_x, g_y, 1, g_x * g_y % p)
+
+
+def point_compress(P):
+    zinv = modp_inv(P[2])
+    x = P[0] * zinv % p
+    y = P[1] * zinv % p
+    return int.to_bytes(y | ((x & 1) << 255), 32, "little")
+
+
+def point_decompress(s):
+    if len(s) != 32:
+        raise Exception("Invalid input length for decompression")
+    y = int.from_bytes(s, "little")
+    sign = y >> 255
+    y &= (1 << 255) - 1
+
+
+
+Josefsson & Moeller      Expires August 26, 2015               [Page 21]
+
+ 
+Internet-Draft               EdDSA & Ed25519               February 2015
+
+
+    x = recover_x(y, sign)
+    if x is None:
+        return None
+    else:
+        return (x, y, 1, x*y % p)
+
+
+def secret_expand(secret):
+    if len(secret) != 32:
+        raise Exception("Bad size of private key")
+    h = sha512(secret)
+    a = int.from_bytes(h[:32], "little")
+    a &= (1 << 254) - 8
+    a |= (1 << 254)
+    return (a, h[32:])
+
+
+def secret_to_public(secret):
+    (a, dummy) = secret_expand(secret)
+    return point_compress(point_mul(a, G))
+
+
+def sign(secret, msg):
+    a, prefix = secret_expand(secret)
+    A = point_compress(point_mul(a, G))
+    r = sha512_modq(prefix + msg)
+    R = point_mul(r, G)
+    Rs = point_compress(R)
+    h = sha512_modq(Rs + A + msg)
+    s = (r + h * a) % q
+    return Rs + int.to_bytes(s, 32, "little")
+
+
+def verify(public, msg, signature):
+    if len(public) != 32:
+        raise Exception("Bad public-key length")
+    if len(signature) != 64:
+        Exception("Bad signature length")
+    A = point_decompress(public)
+    if not A:
+        return False
+    Rs = signature[:32]
+    R = point_decompress(Rs)
+    if not R:
+        return False
+    s = int.from_bytes(signature[32:], "little")
+    h = sha512_modq(Rs + public + msg)
+    sB = point_mul(s, G)
+
+
+
+Josefsson & Moeller      Expires August 26, 2015               [Page 22]
+
+ 
+Internet-Draft               EdDSA & Ed25519               February 2015
+
+
+    hA = point_mul(h, A)
+    return point_equal(sB, point_add(R, hA))
+
+Appendix B.  Library driver
+
+
+   Below is a command-line tool that uses the library above to perform
+   computations, for interactive use or for self-checking.
+
+   import sys
+   import binascii
+
+   from ed25519 import *
+
+   def point_valid(P):
+       zinv = modp_inv(P[2])
+       x = P[0] * zinv % p
+       y = P[1] * zinv % p
+       assert (x*y - P[3]*zinv) % p == 0
+       return (-x*x + y*y - 1 - d*x*x*y*y) % p == 0
+
+   assert point_valid(G)
+   Z = (0, 1, 1, 0)
+   assert point_valid(Z)
+
+   assert point_equal(Z, point_add(Z, Z))
+   assert point_equal(G, point_add(Z, G))
+   assert point_equal(Z, point_mul(0, G))
+   assert point_equal(G, point_mul(1, G))
+   assert point_equal(point_add(G, G), point_mul(2, G))
+   for i in range(0, 100):
+       assert point_valid(point_mul(i, G))
+   assert point_equal(Z, point_mul(q, G))
+
+   def munge_string(s, pos, change):
+       return (s[:pos] +
+               int.to_bytes(s[pos] ^ change, 1, "little") +
+               s[pos+1:])
+
+   # Read a file in the format of
+   # http://ed25519.cr.yp.to/python/sign.input
+   lineno = 0
+   while True:
+       line = sys.stdin.readline()
+       if not line:
+           break
+       lineno = lineno + 1
+       print(lineno)
+       fields = line.split(":")
+
+
+
+Josefsson & Moeller      Expires August 26, 2015               [Page 23]
+
+ 
+Internet-Draft               EdDSA & Ed25519               February 2015
+
+
+       secret = (binascii.unhexlify(fields[0]))[:32]
+       public = binascii.unhexlify(fields[1])
+       msg = binascii.unhexlify(fields[2])
+       signature = binascii.unhexlify(fields[3])[:64]
+
+       assert public == secret_to_public(secret)
+       assert signature == sign(secret, msg)
+       assert verify(public, msg, signature)
+       if len(msg) == 0:
+           bad_msg = b"x"
+       else:
+           bad_msg = munge_string(msg, len(msg) // 3, 4)
+       assert not verify(public, bad_msg, signature)
+       bad_signature = munge_string(signature, 20, 8)
+       assert not verify(public, msg, bad_signature)
+       bad_signature = munge_string(signature, 40, 16)
+       assert not verify(public, msg, bad_signature)
+
+Authors' Addresses
+
+   Simon Josefsson
+   SJD AB
+
+   Email: simon@josefsson.org
+   URI:   http://josefsson.org/
+
+
+   Niels Moeller
+
+   Email: nisse@lysator.liu.se
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Josefsson & Moeller      Expires August 26, 2015               [Page 24]
+
+
+
+Html markup produced by rfcmarkup 1.113, available from https://tools.ietf.org/tools/rfcmarkup/  
diff --git a/crypt/monero_crypto/crypto_ops_builder/include/Makefile.am b/crypt/monero_crypto/crypto_ops_builder/include/Makefile.am
new file mode 100644
index 0000000000..894c371a37
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/include/Makefile.am
@@ -0,0 +1,62 @@
+
+SODIUM_EXPORT = \
+	sodium.h \
+	sodium/core.h \
+	sodium/crypto_aead_chacha20poly1305.h \
+	sodium/crypto_auth.h \
+	sodium/crypto_auth_hmacsha256.h \
+	sodium/crypto_auth_hmacsha512.h \
+	sodium/crypto_auth_hmacsha512256.h \
+	sodium/crypto_box.h \
+	sodium/crypto_box_curve25519xsalsa20poly1305.h \
+	sodium/crypto_core_hsalsa20.h \
+	sodium/crypto_core_salsa20.h \
+	sodium/crypto_core_salsa2012.h \
+	sodium/crypto_core_salsa208.h \
+	sodium/crypto_generichash.h \
+	sodium/crypto_generichash_blake2b.h \
+	sodium/crypto_hash.h \
+	sodium/crypto_hash_sha256.h \
+	sodium/crypto_hash_sha512.h \
+	sodium/crypto_onetimeauth.h \
+	sodium/crypto_onetimeauth_poly1305.h \
+	sodium/crypto_pwhash_scryptsalsa208sha256.h \
+	sodium/crypto_scalarmult.h \
+	sodium/crypto_scalarmult_curve25519.h \
+	sodium/crypto_secretbox.h \
+	sodium/crypto_secretbox_xsalsa20poly1305.h \
+	sodium/crypto_shorthash.h \
+	sodium/crypto_shorthash_siphash24.h \
+	sodium/crypto_sign.h \
+	sodium/crypto_sign_ed25519.h \
+	sodium/crypto_sign_edwards25519sha512batch.h \
+	sodium/crypto_stream.h \
+	sodium/crypto_stream_aes128ctr.h \
+	sodium/crypto_stream_chacha20.h \
+	sodium/crypto_stream_salsa20.h \
+	sodium/crypto_stream_salsa2012.h \
+	sodium/crypto_stream_salsa208.h \
+	sodium/crypto_stream_xsalsa20.h \
+	sodium/crypto_int32.h \
+	sodium/crypto_int64.h \
+	sodium/crypto_uint16.h \
+	sodium/crypto_uint32.h \
+	sodium/crypto_uint64.h \
+	sodium/crypto_uint8.h \
+	sodium/crypto_verify_16.h \
+	sodium/crypto_verify_32.h \
+	sodium/crypto_verify_64.h \
+	sodium/export.h \
+	sodium/randombytes.h \
+	sodium/randombytes_salsa20_random.h \
+	sodium/randombytes_sysrandom.h \
+	sodium/runtime.h \
+	sodium/utils.h
+
+EXTRA_SRC = $(SODIUM_EXPORT) \
+	sodium/version.h.in
+
+nobase_include_HEADERS = $(SODIUM_EXPORT)
+
+nobase_nodist_include_HEADERS = \
+	sodium/version.h
diff --git a/crypt/monero_crypto/crypto_ops_builder/include/libsodium_LICENSE b/crypt/monero_crypto/crypto_ops_builder/include/libsodium_LICENSE
new file mode 100644
index 0000000000..3edb000f65
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/include/libsodium_LICENSE
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2013-2015
+ * Frank Denis <j at pureftpd dot org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
diff --git a/crypt/monero_crypto/crypto_ops_builder/include/sodium.h b/crypt/monero_crypto/crypto_ops_builder/include/sodium.h
new file mode 100644
index 0000000000..207bdedeb6
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/include/sodium.h
@@ -0,0 +1,50 @@
+
+#ifndef sodium_H
+#define sodium_H
+
+#include "sodium/core.h"
+#include "sodium/crypto_aead_chacha20poly1305.h"
+#include "sodium/crypto_auth.h"
+#include "sodium/crypto_auth_hmacsha256.h"
+#include "sodium/crypto_auth_hmacsha512.h"
+#include "sodium/crypto_auth_hmacsha512256.h"
+#include "sodium/crypto_box.h"
+#include "sodium/crypto_box_curve25519xsalsa20poly1305.h"
+#include "sodium/crypto_core_hsalsa20.h"
+#include "sodium/crypto_core_salsa20.h"
+#include "sodium/crypto_core_salsa2012.h"
+#include "sodium/crypto_core_salsa208.h"
+#include "sodium/crypto_generichash.h"
+#include "sodium/crypto_generichash_blake2b.h"
+#include "sodium/crypto_hash.h"
+#include "sodium/crypto_hash_sha256.h"
+#include "sodium/crypto_hash_sha512.h"
+#include "sodium/crypto_onetimeauth.h"
+#include "sodium/crypto_onetimeauth_poly1305.h"
+#include "sodium/crypto_pwhash_scryptsalsa208sha256.h"
+#include "sodium/crypto_scalarmult.h"
+#include "sodium/crypto_scalarmult_curve25519.h"
+#include "sodium/crypto_secretbox.h"
+#include "sodium/crypto_secretbox_xsalsa20poly1305.h"
+#include "sodium/crypto_shorthash.h"
+#include "sodium/crypto_shorthash_siphash24.h"
+#include "sodium/crypto_sign.h"
+#include "sodium/crypto_sign_ed25519.h"
+#include "sodium/crypto_stream.h"
+#include "sodium/crypto_stream_aes128ctr.h"
+#include "sodium/crypto_stream_chacha20.h"
+#include "sodium/crypto_stream_salsa20.h"
+#include "sodium/crypto_stream_salsa2012.h"
+#include "sodium/crypto_stream_salsa208.h"
+#include "sodium/crypto_stream_xsalsa20.h"
+#include "sodium/crypto_verify_16.h"
+#include "sodium/crypto_verify_32.h"
+#include "sodium/crypto_verify_64.h"
+#include "sodium/randombytes.h"
+#include "sodium/randombytes_salsa20_random.h"
+#include "sodium/randombytes_sysrandom.h"
+#include "sodium/runtime.h"
+#include "sodium/utils.h"
+#include "sodium/version.h"
+
+#endif
diff --git a/crypt/monero_crypto/crypto_ops_builder/include/sodium/crypto_int32.h b/crypt/monero_crypto/crypto_ops_builder/include/sodium/crypto_int32.h
new file mode 100644
index 0000000000..a22019d87c
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/include/sodium/crypto_int32.h
@@ -0,0 +1,8 @@
+#ifndef crypto_int32_H
+#define crypto_int32_H
+
+#include <stdint.h>
+
+typedef int32_t crypto_int32;
+
+#endif
diff --git a/crypt/monero_crypto/crypto_ops_builder/include/sodium/crypto_int64.h b/crypt/monero_crypto/crypto_ops_builder/include/sodium/crypto_int64.h
new file mode 100644
index 0000000000..f68a283611
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/include/sodium/crypto_int64.h
@@ -0,0 +1,8 @@
+#ifndef crypto_int64_H
+#define crypto_int64_H
+
+#include <stdint.h>
+
+typedef int64_t crypto_int64;
+
+#endif
diff --git a/crypt/monero_crypto/crypto_ops_builder/include/sodium/crypto_uint16.h b/crypt/monero_crypto/crypto_ops_builder/include/sodium/crypto_uint16.h
new file mode 100644
index 0000000000..6be4e347c6
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/include/sodium/crypto_uint16.h
@@ -0,0 +1,8 @@
+#ifndef crypto_uint16_H
+#define crypto_uint16_H
+
+#include <stdint.h>
+
+typedef uint16_t crypto_uint16;
+
+#endif
diff --git a/crypt/monero_crypto/crypto_ops_builder/include/sodium/crypto_uint32.h b/crypt/monero_crypto/crypto_ops_builder/include/sodium/crypto_uint32.h
new file mode 100644
index 0000000000..ba66cecc65
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/include/sodium/crypto_uint32.h
@@ -0,0 +1,8 @@
+#ifndef crypto_uint32_H
+#define crypto_uint32_H
+
+#include <stdint.h>
+
+typedef uint32_t crypto_uint32;
+
+#endif
diff --git a/crypt/monero_crypto/crypto_ops_builder/include/sodium/crypto_uint64.h b/crypt/monero_crypto/crypto_ops_builder/include/sodium/crypto_uint64.h
new file mode 100644
index 0000000000..98b3f6d344
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/include/sodium/crypto_uint64.h
@@ -0,0 +1,8 @@
+#ifndef crypto_uint64_H
+#define crypto_uint64_H
+
+#include <stdint.h>
+
+typedef uint64_t crypto_uint64;
+
+#endif
diff --git a/crypt/monero_crypto/crypto_ops_builder/include/sodium/crypto_uint8.h b/crypt/monero_crypto/crypto_ops_builder/include/sodium/crypto_uint8.h
new file mode 100644
index 0000000000..789613ba5f
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/include/sodium/crypto_uint8.h
@@ -0,0 +1,8 @@
+#ifndef crypto_uint8_H
+#define crypto_uint8_H
+
+#include <stdint.h>
+
+typedef uint8_t crypto_uint8;
+
+#endif
diff --git a/crypt/monero_crypto/crypto_ops_builder/include/sodium/crypto_verify_32.h b/crypt/monero_crypto/crypto_ops_builder/include/sodium/crypto_verify_32.h
new file mode 100644
index 0000000000..58e4d0e829
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/include/sodium/crypto_verify_32.h
@@ -0,0 +1,22 @@
+#ifndef crypto_verify_32_H
+#define crypto_verify_32_H
+
+#include <stddef.h>
+#include "export.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define crypto_verify_32_BYTES 32U
+SODIUM_EXPORT
+size_t crypto_verify_32_bytes(void);
+
+SODIUM_EXPORT
+int crypto_verify_32(const unsigned char *x, const unsigned char *y);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/crypt/monero_crypto/crypto_ops_builder/include/sodium/randombytes.h b/crypt/monero_crypto/crypto_ops_builder/include/sodium/randombytes.h
new file mode 100644
index 0000000000..08aff05259
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/include/sodium/randombytes.h
@@ -0,0 +1,58 @@
+
+#ifndef randombytes_H
+#define randombytes_H
+
+#include <sys/types.h>
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "export.h"
+
+#ifdef __cplusplus
+# if __GNUC__
+#  pragma GCC diagnostic ignored "-Wlong-long"
+# endif
+extern "C" {
+#endif
+
+typedef struct randombytes_implementation {
+    const char *(*implementation_name)(void); /* required */
+    uint32_t    (*random)(void);              /* required */
+    void        (*stir)(void);                /* optional */
+    uint32_t    (*uniform)(const uint32_t upper_bound); /* optional, a default implementation will be used if NULL */
+    void        (*buf)(void * const buf, const size_t size); /* required */
+    int         (*close)(void);               /* optional */
+} randombytes_implementation;
+
+SODIUM_EXPORT
+void randombytes_buf(void * const buf, const size_t size);
+
+SODIUM_EXPORT
+uint32_t randombytes_random(void);
+
+SODIUM_EXPORT
+uint32_t randombytes_uniform(const uint32_t upper_bound);
+
+SODIUM_EXPORT
+void randombytes_stir(void);
+
+SODIUM_EXPORT
+int randombytes_close(void);
+
+SODIUM_EXPORT
+int randombytes_set_implementation(randombytes_implementation *impl);
+
+SODIUM_EXPORT
+const char *randombytes_implementation_name(void);
+
+/* -- NaCl compatibility interface -- */
+
+SODIUM_EXPORT
+void randombytes(unsigned char * const buf, const unsigned long long buf_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/crypt/monero_crypto/crypto_ops_builder/randombytes.c b/crypt/monero_crypto/crypto_ops_builder/randombytes.c
new file mode 100755
index 0000000000..fa7d42149d
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/randombytes.c
@@ -0,0 +1,52 @@
+#ifndef _WIN32
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+/* it's really stupid that there isn't a syscall for this */
+
+static int ed25519_random_fd = -1;
+
+static inline void ed25519_randombytes(unsigned char *x,unsigned long long xlen)
+{
+  int i;
+
+  if (ed25519_random_fd == -1) {
+    for (;;) {
+      ed25519_random_fd = open("/dev/urandom",O_RDONLY);
+      if (ed25519_random_fd != -1) break;
+      sleep(1);
+    }
+  }
+
+  while (xlen > 0) {
+    if (xlen < 1048576) i = xlen; else i = 1048576;
+
+    i = read(ed25519_random_fd,x,i);
+    if (i < 1) {
+      sleep(1);
+      continue;
+    }
+
+    x += i;
+    xlen -= i;
+  }
+}
+
+#else
+#include <windows.h>
+#include <wincrypt.h>
+
+static inline void ed25519_randombytes(unsigned char *x,unsigned long long xlen)
+{
+  HCRYPTPROV prov = 0;
+
+  CryptAcquireContextW(&prov, NULL, NULL,
+    PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT);
+
+  CryptGenRandom(prov, xlen, x);
+  CryptReleaseContext(prov, 0);
+}
+
+#endif /* _WIN32  */
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/Makefile b/crypt/monero_crypto/crypto_ops_builder/ref10/Makefile
new file mode 100644
index 0000000000..9b0ba7ad45
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/Makefile
@@ -0,0 +1,41 @@
+all: d.h d2.h sqrtm1.h base.h base2.h \
+ge_add.h ge_sub.h \
+ge_madd.h ge_msub.h \
+ge_p2_dbl.h \
+pow225521.h pow22523.h
+
+d.h: d.py
+	python d.py > d.h
+
+d2.h: d2.py
+	python d2.py > d2.h
+
+sqrtm1.h: sqrtm1.py
+	python sqrtm1.py > sqrtm1.h
+
+base.h: base.py
+	python base.py > base.h
+
+base2.h: base2.py
+	python base2.py > base2.h
+
+ge_add.h: ge_add.q q2h.sh
+	./q2h.sh < ge_add.q > ge_add.h
+
+ge_sub.h: ge_sub.q q2h.sh
+	./q2h.sh < ge_sub.q > ge_sub.h
+
+ge_madd.h: ge_madd.q q2h.sh
+	./q2h.sh < ge_madd.q > ge_madd.h
+
+ge_msub.h: ge_msub.q q2h.sh
+	./q2h.sh < ge_msub.q > ge_msub.h
+
+ge_p2_dbl.h: ge_p2_dbl.q q2h.sh
+	./q2h.sh < ge_p2_dbl.q > ge_p2_dbl.h
+
+pow22523.h: pow22523.q q2h.sh
+	./q2h.sh < pow22523.q > pow22523.h
+
+pow225521.h: pow225521.q q2h.sh
+	./q2h.sh < pow225521.q > pow225521.h
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/api.h b/crypt/monero_crypto/crypto_ops_builder/ref10/api.h
new file mode 100644
index 0000000000..d88dae0c32
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/api.h
@@ -0,0 +1,4 @@
+#define CRYPTO_SECRETKEYBYTES 64
+#define CRYPTO_PUBLICKEYBYTES 32
+#define CRYPTO_BYTES 64
+#define CRYPTO_DETERMINISTIC 1
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/base.h b/crypt/monero_crypto/crypto_ops_builder/ref10/base.h
new file mode 100644
index 0000000000..573bd8a05c
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/base.h
@@ -0,0 +1,1344 @@
+{
+ {
+  { 25967493,-14356035,29566456,3660896,-12694345,4014787,27544626,-11754271,-6079156,2047605 },
+  { -12545711,934262,-2722910,3049990,-727428,9406986,12720692,5043384,19500929,-15469378 },
+  { -8738181,4489570,9688441,-14785194,10184609,-12363380,29287919,11864899,-24514362,-4438546 },
+ },
+ {
+  { -12815894,-12976347,-21581243,11784320,-25355658,-2750717,-11717903,-3814571,-358445,-10211303 },
+  { -21703237,6903825,27185491,6451973,-29577724,-9554005,-15616551,11189268,-26829678,-5319081 },
+  { 26966642,11152617,32442495,15396054,14353839,-12752335,-3128826,-9541118,-15472047,-4166697 },
+ },
+ {
+  { 15636291,-9688557,24204773,-7912398,616977,-16685262,27787600,-14772189,28944400,-1550024 },
+  { 16568933,4717097,-11556148,-1102322,15682896,-11807043,16354577,-11775962,7689662,11199574 },
+  { 30464156,-5976125,-11779434,-15670865,23220365,15915852,7512774,10017326,-17749093,-9920357 },
+ },
+ {
+  { -17036878,13921892,10945806,-6033431,27105052,-16084379,-28926210,15006023,3284568,-6276540 },
+  { 23599295,-8306047,-11193664,-7687416,13236774,10506355,7464579,9656445,13059162,10374397 },
+  { 7798556,16710257,3033922,2874086,28997861,2835604,32406664,-3839045,-641708,-101325 },
+ },
+ {
+  { 10861363,11473154,27284546,1981175,-30064349,12577861,32867885,14515107,-15438304,10819380 },
+  { 4708026,6336745,20377586,9066809,-11272109,6594696,-25653668,12483688,-12668491,5581306 },
+  { 19563160,16186464,-29386857,4097519,10237984,-4348115,28542350,13850243,-23678021,-15815942 },
+ },
+ {
+  { -15371964,-12862754,32573250,4720197,-26436522,5875511,-19188627,-15224819,-9818940,-12085777 },
+  { -8549212,109983,15149363,2178705,22900618,4543417,3044240,-15689887,1762328,14866737 },
+  { -18199695,-15951423,-10473290,1707278,-17185920,3916101,-28236412,3959421,27914454,4383652 },
+ },
+ {
+  { 5153746,9909285,1723747,-2777874,30523605,5516873,19480852,5230134,-23952439,-15175766 },
+  { -30269007,-3463509,7665486,10083793,28475525,1649722,20654025,16520125,30598449,7715701 },
+  { 28881845,14381568,9657904,3680757,-20181635,7843316,-31400660,1370708,29794553,-1409300 },
+ },
+ {
+  { 14499471,-2729599,-33191113,-4254652,28494862,14271267,30290735,10876454,-33154098,2381726 },
+  { -7195431,-2655363,-14730155,462251,-27724326,3941372,-6236617,3696005,-32300832,15351955 },
+  { 27431194,8222322,16448760,-3907995,-18707002,11938355,-32961401,-2970515,29551813,10109425 },
+ },
+},
+{
+ {
+  { -13657040,-13155431,-31283750,11777098,21447386,6519384,-2378284,-1627556,10092783,-4764171 },
+  { 27939166,14210322,4677035,16277044,-22964462,-12398139,-32508754,12005538,-17810127,12803510 },
+  { 17228999,-15661624,-1233527,300140,-1224870,-11714777,30364213,-9038194,18016357,4397660 },
+ },
+ {
+  { -10958843,-7690207,4776341,-14954238,27850028,-15602212,-26619106,14544525,-17477504,982639 },
+  { 29253598,15796703,-2863982,-9908884,10057023,3163536,7332899,-4120128,-21047696,9934963 },
+  { 5793303,16271923,-24131614,-10116404,29188560,1206517,-14747930,4559895,-30123922,-10897950 },
+ },
+ {
+  { -27643952,-11493006,16282657,-11036493,28414021,-15012264,24191034,4541697,-13338309,5500568 },
+  { 12650548,-1497113,9052871,11355358,-17680037,-8400164,-17430592,12264343,10874051,13524335 },
+  { 25556948,-3045990,714651,2510400,23394682,-10415330,33119038,5080568,-22528059,5376628 },
+ },
+ {
+  { -26088264,-4011052,-17013699,-3537628,-6726793,1920897,-22321305,-9447443,4535768,1569007 },
+  { -2255422,14606630,-21692440,-8039818,28430649,8775819,-30494562,3044290,31848280,12543772 },
+  { -22028579,2943893,-31857513,6777306,13784462,-4292203,-27377195,-2062731,7718482,14474653 },
+ },
+ {
+  { 2385315,2454213,-22631320,46603,-4437935,-15680415,656965,-7236665,24316168,-5253567 },
+  { 13741529,10911568,-33233417,-8603737,-20177830,-1033297,33040651,-13424532,-20729456,8321686 },
+  { 21060490,-2212744,15712757,-4336099,1639040,10656336,23845965,-11874838,-9984458,608372 },
+ },
+ {
+  { -13672732,-15087586,-10889693,-7557059,-6036909,11305547,1123968,-6780577,27229399,23887 },
+  { -23244140,-294205,-11744728,14712571,-29465699,-2029617,12797024,-6440308,-1633405,16678954 },
+  { -29500620,4770662,-16054387,14001338,7830047,9564805,-1508144,-4795045,-17169265,4904953 },
+ },
+ {
+  { 24059557,14617003,19037157,-15039908,19766093,-14906429,5169211,16191880,2128236,-4326833 },
+  { -16981152,4124966,-8540610,-10653797,30336522,-14105247,-29806336,916033,-6882542,-2986532 },
+  { -22630907,12419372,-7134229,-7473371,-16478904,16739175,285431,2763829,15736322,4143876 },
+ },
+ {
+  { 2379352,11839345,-4110402,-5988665,11274298,794957,212801,-14594663,23527084,-16458268 },
+  { 33431127,-11130478,-17838966,-15626900,8909499,8376530,-32625340,4087881,-15188911,-14416214 },
+  { 1767683,7197987,-13205226,-2022635,-13091350,448826,5799055,4357868,-4774191,-16323038 },
+ },
+},
+{
+ {
+  { 6721966,13833823,-23523388,-1551314,26354293,-11863321,23365147,-3949732,7390890,2759800 },
+  { 4409041,2052381,23373853,10530217,7676779,-12885954,21302353,-4264057,1244380,-12919645 },
+  { -4421239,7169619,4982368,-2957590,30256825,-2777540,14086413,9208236,15886429,16489664 },
+ },
+ {
+  { 1996075,10375649,14346367,13311202,-6874135,-16438411,-13693198,398369,-30606455,-712933 },
+  { -25307465,9795880,-2777414,14878809,-33531835,14780363,13348553,12076947,-30836462,5113182 },
+  { -17770784,11797796,31950843,13929123,-25888302,12288344,-30341101,-7336386,13847711,5387222 },
+ },
+ {
+  { -18582163,-3416217,17824843,-2340966,22744343,-10442611,8763061,3617786,-19600662,10370991 },
+  { 20246567,-14369378,22358229,-543712,18507283,-10413996,14554437,-8746092,32232924,16763880 },
+  { 9648505,10094563,26416693,14745928,-30374318,-6472621,11094161,15689506,3140038,-16510092 },
+ },
+ {
+  { -16160072,5472695,31895588,4744994,8823515,10365685,-27224800,9448613,-28774454,366295 },
+  { 19153450,11523972,-11096490,-6503142,-24647631,5420647,28344573,8041113,719605,11671788 },
+  { 8678025,2694440,-6808014,2517372,4964326,11152271,-15432916,-15266516,27000813,-10195553 },
+ },
+ {
+  { -15157904,7134312,8639287,-2814877,-7235688,10421742,564065,5336097,6750977,-14521026 },
+  { 11836410,-3979488,26297894,16080799,23455045,15735944,1695823,-8819122,8169720,16220347 },
+  { -18115838,8653647,17578566,-6092619,-8025777,-16012763,-11144307,-2627664,-5990708,-14166033 },
+ },
+ {
+  { -23308498,-10968312,15213228,-10081214,-30853605,-11050004,27884329,2847284,2655861,1738395 },
+  { -27537433,-14253021,-25336301,-8002780,-9370762,8129821,21651608,-3239336,-19087449,-11005278 },
+  { 1533110,3437855,23735889,459276,29970501,11335377,26030092,5821408,10478196,8544890 },
+ },
+ {
+  { 32173121,-16129311,24896207,3921497,22579056,-3410854,19270449,12217473,17789017,-3395995 },
+  { -30552961,-2228401,-15578829,-10147201,13243889,517024,15479401,-3853233,30460520,1052596 },
+  { -11614875,13323618,32618793,8175907,-15230173,12596687,27491595,-4612359,3179268,-9478891 },
+ },
+ {
+  { 31947069,-14366651,-4640583,-15339921,-15125977,-6039709,-14756777,-16411740,19072640,-9511060 },
+  { 11685058,11822410,3158003,-13952594,33402194,-4165066,5977896,-5215017,473099,5040608 },
+  { -20290863,8198642,-27410132,11602123,1290375,-2799760,28326862,1721092,-19558642,-3131606 },
+ },
+},
+{
+ {
+  { 7881532,10687937,7578723,7738378,-18951012,-2553952,21820786,8076149,-27868496,11538389 },
+  { -19935666,3899861,18283497,-6801568,-15728660,-11249211,8754525,7446702,-5676054,5797016 },
+  { -11295600,-3793569,-15782110,-7964573,12708869,-8456199,2014099,-9050574,-2369172,-5877341 },
+ },
+ {
+  { -22472376,-11568741,-27682020,1146375,18956691,16640559,1192730,-3714199,15123619,10811505 },
+  { 14352098,-3419715,-18942044,10822655,32750596,4699007,-70363,15776356,-28886779,-11974553 },
+  { -28241164,-8072475,-4978962,-5315317,29416931,1847569,-20654173,-16484855,4714547,-9600655 },
+ },
+ {
+  { 15200332,8368572,19679101,15970074,-31872674,1959451,24611599,-4543832,-11745876,12340220 },
+  { 12876937,-10480056,33134381,6590940,-6307776,14872440,9613953,8241152,15370987,9608631 },
+  { -4143277,-12014408,8446281,-391603,4407738,13629032,-7724868,15866074,-28210621,-8814099 },
+ },
+ {
+  { 26660628,-15677655,8393734,358047,-7401291,992988,-23904233,858697,20571223,8420556 },
+  { 14620715,13067227,-15447274,8264467,14106269,15080814,33531827,12516406,-21574435,-12476749 },
+  { 236881,10476226,57258,-14677024,6472998,2466984,17258519,7256740,8791136,15069930 },
+ },
+ {
+  { 1276410,-9371918,22949635,-16322807,-23493039,-5702186,14711875,4874229,-30663140,-2331391 },
+  { 5855666,4990204,-13711848,7294284,-7804282,1924647,-1423175,-7912378,-33069337,9234253 },
+  { 20590503,-9018988,31529744,-7352666,-2706834,10650548,31559055,-11609587,18979186,13396066 },
+ },
+ {
+  { 24474287,4968103,22267082,4407354,24063882,-8325180,-18816887,13594782,33514650,7021958 },
+  { -11566906,-6565505,-21365085,15928892,-26158305,4315421,-25948728,-3916677,-21480480,12868082 },
+  { -28635013,13504661,19988037,-2132761,21078225,6443208,-21446107,2244500,-12455797,-8089383 },
+ },
+ {
+  { -30595528,13793479,-5852820,319136,-25723172,-6263899,33086546,8957937,-15233648,5540521 },
+  { -11630176,-11503902,-8119500,-7643073,2620056,1022908,-23710744,-1568984,-16128528,-14962807 },
+  { 23152971,775386,27395463,14006635,-9701118,4649512,1689819,892185,-11513277,-15205948 },
+ },
+ {
+  { 9770129,9586738,26496094,4324120,1556511,-3550024,27453819,4763127,-19179614,5867134 },
+  { -32765025,1927590,31726409,-4753295,23962434,-16019500,27846559,5931263,-29749703,-16108455 },
+  { 27461885,-2977536,22380810,1815854,-23033753,-3031938,7283490,-15148073,-19526700,7734629 },
+ },
+},
+{
+ {
+  { -8010264,-9590817,-11120403,6196038,29344158,-13430885,7585295,-3176626,18549497,15302069 },
+  { -32658337,-6171222,-7672793,-11051681,6258878,13504381,10458790,-6418461,-8872242,8424746 },
+  { 24687205,8613276,-30667046,-3233545,1863892,-1830544,19206234,7134917,-11284482,-828919 },
+ },
+ {
+  { 11334899,-9218022,8025293,12707519,17523892,-10476071,10243738,-14685461,-5066034,16498837 },
+  { 8911542,6887158,-9584260,-6958590,11145641,-9543680,17303925,-14124238,6536641,10543906 },
+  { -28946384,15479763,-17466835,568876,-1497683,11223454,-2669190,-16625574,-27235709,8876771 },
+ },
+ {
+  { -25742899,-12566864,-15649966,-846607,-33026686,-796288,-33481822,15824474,-604426,-9039817 },
+  { 10330056,70051,7957388,-9002667,9764902,15609756,27698697,-4890037,1657394,3084098 },
+  { 10477963,-7470260,12119566,-13250805,29016247,-5365589,31280319,14396151,-30233575,15272409 },
+ },
+ {
+  { -12288309,3169463,28813183,16658753,25116432,-5630466,-25173957,-12636138,-25014757,1950504 },
+  { -26180358,9489187,11053416,-14746161,-31053720,5825630,-8384306,-8767532,15341279,8373727 },
+  { 28685821,7759505,-14378516,-12002860,-31971820,4079242,298136,-10232602,-2878207,15190420 },
+ },
+ {
+  { -32932876,13806336,-14337485,-15794431,-24004620,10940928,8669718,2742393,-26033313,-6875003 },
+  { -1580388,-11729417,-25979658,-11445023,-17411874,-10912854,9291594,-16247779,-12154742,6048605 },
+  { -30305315,14843444,1539301,11864366,20201677,1900163,13934231,5128323,11213262,9168384 },
+ },
+ {
+  { -26280513,11007847,19408960,-940758,-18592965,-4328580,-5088060,-11105150,20470157,-16398701 },
+  { -23136053,9282192,14855179,-15390078,-7362815,-14408560,-22783952,14461608,14042978,5230683 },
+  { 29969567,-2741594,-16711867,-8552442,9175486,-2468974,21556951,3506042,-5933891,-12449708 },
+ },
+ {
+  { -3144746,8744661,19704003,4581278,-20430686,6830683,-21284170,8971513,-28539189,15326563 },
+  { -19464629,10110288,-17262528,-3503892,-23500387,1355669,-15523050,15300988,-20514118,9168260 },
+  { -5353335,4488613,-23803248,16314347,7780487,-15638939,-28948358,9601605,33087103,-9011387 },
+ },
+ {
+  { -19443170,-15512900,-20797467,-12445323,-29824447,10229461,-27444329,-15000531,-5996870,15664672 },
+  { 23294591,-16632613,-22650781,-8470978,27844204,11461195,13099750,-2460356,18151676,13417686 },
+  { -24722913,-4176517,-31150679,5988919,-26858785,6685065,1661597,-12551441,15271676,-15452665 },
+ },
+},
+{
+ {
+  { 11433042,-13228665,8239631,-5279517,-1985436,-725718,-18698764,2167544,-6921301,-13440182 },
+  { -31436171,15575146,30436815,12192228,-22463353,9395379,-9917708,-8638997,12215110,12028277 },
+  { 14098400,6555944,23007258,5757252,-15427832,-12950502,30123440,4617780,-16900089,-655628 },
+ },
+ {
+  { -4026201,-15240835,11893168,13718664,-14809462,1847385,-15819999,10154009,23973261,-12684474 },
+  { -26531820,-3695990,-1908898,2534301,-31870557,-16550355,18341390,-11419951,32013174,-10103539 },
+  { -25479301,10876443,-11771086,-14625140,-12369567,1838104,21911214,6354752,4425632,-837822 },
+ },
+ {
+  { -10433389,-14612966,22229858,-3091047,-13191166,776729,-17415375,-12020462,4725005,14044970 },
+  { 19268650,-7304421,1555349,8692754,-21474059,-9910664,6347390,-1411784,-19522291,-16109756 },
+  { -24864089,12986008,-10898878,-5558584,-11312371,-148526,19541418,8180106,9282262,10282508 },
+ },
+ {
+  { -26205082,4428547,-8661196,-13194263,4098402,-14165257,15522535,8372215,5542595,-10702683 },
+  { -10562541,14895633,26814552,-16673850,-17480754,-2489360,-2781891,6993761,-18093885,10114655 },
+  { -20107055,-929418,31422704,10427861,-7110749,6150669,-29091755,-11529146,25953725,-106158 },
+ },
+ {
+  { -4234397,-8039292,-9119125,3046000,2101609,-12607294,19390020,6094296,-3315279,12831125 },
+  { -15998678,7578152,5310217,14408357,-33548620,-224739,31575954,6326196,7381791,-2421839 },
+  { -20902779,3296811,24736065,-16328389,18374254,7318640,6295303,8082724,-15362489,12339664 },
+ },
+ {
+  { 27724736,2291157,6088201,-14184798,1792727,5857634,13848414,15768922,25091167,14856294 },
+  { -18866652,8331043,24373479,8541013,-701998,-9269457,12927300,-12695493,-22182473,-9012899 },
+  { -11423429,-5421590,11632845,3405020,30536730,-11674039,-27260765,13866390,30146206,9142070 },
+ },
+ {
+  { 3924129,-15307516,-13817122,-10054960,12291820,-668366,-27702774,9326384,-8237858,4171294 },
+  { -15921940,16037937,6713787,16606682,-21612135,2790944,26396185,3731949,345228,-5462949 },
+  { -21327538,13448259,25284571,1143661,20614966,-8849387,2031539,-12391231,-16253183,-13582083 },
+ },
+ {
+  { 31016211,-16722429,26371392,-14451233,-5027349,14854137,17477601,3842657,28012650,-16405420 },
+  { -5075835,9368966,-8562079,-4600902,-15249953,6970560,-9189873,16292057,-8867157,3507940 },
+  { 29439664,3537914,23333589,6997794,-17555561,-11018068,-15209202,-15051267,-9164929,6580396 },
+ },
+},
+{
+ {
+  { -12185861,-7679788,16438269,10826160,-8696817,-6235611,17860444,-9273846,-2095802,9304567 },
+  { 20714564,-4336911,29088195,7406487,11426967,-5095705,14792667,-14608617,5289421,-477127 },
+  { -16665533,-10650790,-6160345,-13305760,9192020,-1802462,17271490,12349094,26939669,-3752294 },
+ },
+ {
+  { -12889898,9373458,31595848,16374215,21471720,13221525,-27283495,-12348559,-3698806,117887 },
+  { 22263325,-6560050,3984570,-11174646,-15114008,-566785,28311253,5358056,-23319780,541964 },
+  { 16259219,3261970,2309254,-15534474,-16885711,-4581916,24134070,-16705829,-13337066,-13552195 },
+ },
+ {
+  { 9378160,-13140186,-22845982,-12745264,28198281,-7244098,-2399684,-717351,690426,14876244 },
+  { 24977353,-314384,-8223969,-13465086,28432343,-1176353,-13068804,-12297348,-22380984,6618999 },
+  { -1538174,11685646,12944378,13682314,-24389511,-14413193,8044829,-13817328,32239829,-5652762 },
+ },
+ {
+  { -18603066,4762990,-926250,8885304,-28412480,-3187315,9781647,-10350059,32779359,5095274 },
+  { -33008130,-5214506,-32264887,-3685216,9460461,-9327423,-24601656,14506724,21639561,-2630236 },
+  { -16400943,-13112215,25239338,15531969,3987758,-4499318,-1289502,-6863535,17874574,558605 },
+ },
+ {
+  { -13600129,10240081,9171883,16131053,-20869254,9599700,33499487,5080151,2085892,5119761 },
+  { -22205145,-2519528,-16381601,414691,-25019550,2170430,30634760,-8363614,-31999993,-5759884 },
+  { -6845704,15791202,8550074,-1312654,29928809,-12092256,27534430,-7192145,-22351378,12961482 },
+ },
+ {
+  { -24492060,-9570771,10368194,11582341,-23397293,-2245287,16533930,8206996,-30194652,-5159638 },
+  { -11121496,-3382234,2307366,6362031,-135455,8868177,-16835630,7031275,7589640,8945490 },
+  { -32152748,8917967,6661220,-11677616,-1192060,-15793393,7251489,-11182180,24099109,-14456170 },
+ },
+ {
+  { 5019558,-7907470,4244127,-14714356,-26933272,6453165,-19118182,-13289025,-6231896,-10280736 },
+  { 10853594,10721687,26480089,5861829,-22995819,1972175,-1866647,-10557898,-3363451,-6441124 },
+  { -17002408,5906790,221599,-6563147,7828208,-13248918,24362661,-2008168,-13866408,7421392 },
+ },
+ {
+  { 8139927,-6546497,32257646,-5890546,30375719,1886181,-21175108,15441252,28826358,-4123029 },
+  { 6267086,9695052,7709135,-16603597,-32869068,-1886135,14795160,-7840124,13746021,-1742048 },
+  { 28584902,7787108,-6732942,-15050729,22846041,-7571236,-3181936,-363524,4771362,-8419958 },
+ },
+},
+{
+ {
+  { 24949256,6376279,-27466481,-8174608,-18646154,-9930606,33543569,-12141695,3569627,11342593 },
+  { 26514989,4740088,27912651,3697550,19331575,-11472339,6809886,4608608,7325975,-14801071 },
+  { -11618399,-14554430,-24321212,7655128,-1369274,5214312,-27400540,10258390,-17646694,-8186692 },
+ },
+ {
+  { 11431204,15823007,26570245,14329124,18029990,4796082,-31446179,15580664,9280358,-3973687 },
+  { -160783,-10326257,-22855316,-4304997,-20861367,-13621002,-32810901,-11181622,-15545091,4387441 },
+  { -20799378,12194512,3937617,-5805892,-27154820,9340370,-24513992,8548137,20617071,-7482001 },
+ },
+ {
+  { -938825,-3930586,-8714311,16124718,24603125,-6225393,-13775352,-11875822,24345683,10325460 },
+  { -19855277,-1568885,-22202708,8714034,14007766,6928528,16318175,-1010689,4766743,3552007 },
+  { -21751364,-16730916,1351763,-803421,-4009670,3950935,3217514,14481909,10988822,-3994762 },
+ },
+ {
+  { 15564307,-14311570,3101243,5684148,30446780,-8051356,12677127,-6505343,-8295852,13296005 },
+  { -9442290,6624296,-30298964,-11913677,-4670981,-2057379,31521204,9614054,-30000824,12074674 },
+  { 4771191,-135239,14290749,-13089852,27992298,14998318,-1413936,-1556716,29832613,-16391035 },
+ },
+ {
+  { 7064884,-7541174,-19161962,-5067537,-18891269,-2912736,25825242,5293297,-27122660,13101590 },
+  { -2298563,2439670,-7466610,1719965,-27267541,-16328445,32512469,-5317593,-30356070,-4190957 },
+  { -30006540,10162316,-33180176,3981723,-16482138,-13070044,14413974,9515896,19568978,9628812 },
+ },
+ {
+  { 33053803,199357,15894591,1583059,27380243,-4580435,-17838894,-6106839,-6291786,3437740 },
+  { -18978877,3884493,19469877,12726490,15913552,13614290,-22961733,70104,7463304,4176122 },
+  { -27124001,10659917,11482427,-16070381,12771467,-6635117,-32719404,-5322751,24216882,5944158 },
+ },
+ {
+  { 8894125,7450974,-2664149,-9765752,-28080517,-12389115,19345746,14680796,11632993,5847885 },
+  { 26942781,-2315317,9129564,-4906607,26024105,11769399,-11518837,6367194,-9727230,4782140 },
+  { 19916461,-4828410,-22910704,-11414391,25606324,-5972441,33253853,8220911,6358847,-1873857 },
+ },
+ {
+  { 801428,-2081702,16569428,11065167,29875704,96627,7908388,-4480480,-13538503,1387155 },
+  { 19646058,5720633,-11416706,12814209,11607948,12749789,14147075,15156355,-21866831,11835260 },
+  { 19299512,1155910,28703737,14890794,2925026,7269399,26121523,15467869,-26560550,5052483 },
+ },
+},
+{
+ {
+  { -3017432,10058206,1980837,3964243,22160966,12322533,-6431123,-12618185,12228557,-7003677 },
+  { 32944382,14922211,-22844894,5188528,21913450,-8719943,4001465,13238564,-6114803,8653815 },
+  { 22865569,-4652735,27603668,-12545395,14348958,8234005,24808405,5719875,28483275,2841751 },
+ },
+ {
+  { -16420968,-1113305,-327719,-12107856,21886282,-15552774,-1887966,-315658,19932058,-12739203 },
+  { -11656086,10087521,-8864888,-5536143,-19278573,-3055912,3999228,13239134,-4777469,-13910208 },
+  { 1382174,-11694719,17266790,9194690,-13324356,9720081,20403944,11284705,-14013818,3093230 },
+ },
+ {
+  { 16650921,-11037932,-1064178,1570629,-8329746,7352753,-302424,16271225,-24049421,-6691850 },
+  { -21911077,-5927941,-4611316,-5560156,-31744103,-10785293,24123614,15193618,-21652117,-16739389 },
+  { -9935934,-4289447,-25279823,4372842,2087473,10399484,31870908,14690798,17361620,11864968 },
+ },
+ {
+  { -11307610,6210372,13206574,5806320,-29017692,-13967200,-12331205,-7486601,-25578460,-16240689 },
+  { 14668462,-12270235,26039039,15305210,25515617,4542480,10453892,6577524,9145645,-6443880 },
+  { 5974874,3053895,-9433049,-10385191,-31865124,3225009,-7972642,3936128,-5652273,-3050304 },
+ },
+ {
+  { 30625386,-4729400,-25555961,-12792866,-20484575,7695099,17097188,-16303496,-27999779,1803632 },
+  { -3553091,9865099,-5228566,4272701,-5673832,-16689700,14911344,12196514,-21405489,7047412 },
+  { 20093277,9920966,-11138194,-5343857,13161587,12044805,-32856851,4124601,-32343828,-10257566 },
+ },
+ {
+  { -20788824,14084654,-13531713,7842147,19119038,-13822605,4752377,-8714640,-21679658,2288038 },
+  { -26819236,-3283715,29965059,3039786,-14473765,2540457,29457502,14625692,-24819617,12570232 },
+  { -1063558,-11551823,16920318,12494842,1278292,-5869109,-21159943,-3498680,-11974704,4724943 },
+ },
+ {
+  { 17960970,-11775534,-4140968,-9702530,-8876562,-1410617,-12907383,-8659932,-29576300,1903856 },
+  { 23134274,-14279132,-10681997,-1611936,20684485,15770816,-12989750,3190296,26955097,14109738 },
+  { 15308788,5320727,-30113809,-14318877,22902008,7767164,29425325,-11277562,31960942,11934971 },
+ },
+ {
+  { -27395711,8435796,4109644,12222639,-24627868,14818669,20638173,4875028,10491392,1379718 },
+  { -13159415,9197841,3875503,-8936108,-1383712,-5879801,33518459,16176658,21432314,12180697 },
+  { -11787308,11500838,13787581,-13832590,-22430679,10140205,1465425,12689540,-10301319,-13872883 },
+ },
+},
+{
+ {
+  { 5414091,-15386041,-21007664,9643570,12834970,1186149,-2622916,-1342231,26128231,6032912 },
+  { -26337395,-13766162,32496025,-13653919,17847801,-12669156,3604025,8316894,-25875034,-10437358 },
+  { 3296484,6223048,24680646,-12246460,-23052020,5903205,-8862297,-4639164,12376617,3188849 },
+ },
+ {
+  { 29190488,-14659046,27549113,-1183516,3520066,-10697301,32049515,-7309113,-16109234,-9852307 },
+  { -14744486,-9309156,735818,-598978,-20407687,-5057904,25246078,-15795669,18640741,-960977 },
+  { -6928835,-16430795,10361374,5642961,4910474,12345252,-31638386,-494430,10530747,1053335 },
+ },
+ {
+  { -29265967,-14186805,-13538216,-12117373,-19457059,-10655384,-31462369,-2948985,24018831,15026644 },
+  { -22592535,-3145277,-2289276,5953843,-13440189,9425631,25310643,13003497,-2314791,-15145616 },
+  { -27419985,-603321,-8043984,-1669117,-26092265,13987819,-27297622,187899,-23166419,-2531735 },
+ },
+ {
+  { -21744398,-13810475,1844840,5021428,-10434399,-15911473,9716667,16266922,-5070217,726099 },
+  { 29370922,-6053998,7334071,-15342259,9385287,2247707,-13661962,-4839461,30007388,-15823341 },
+  { -936379,16086691,23751945,-543318,-1167538,-5189036,9137109,730663,9835848,4555336 },
+ },
+ {
+  { -23376435,1410446,-22253753,-12899614,30867635,15826977,17693930,544696,-11985298,12422646 },
+  { 31117226,-12215734,-13502838,6561947,-9876867,-12757670,-5118685,-4096706,29120153,13924425 },
+  { -17400879,-14233209,19675799,-2734756,-11006962,-5858820,-9383939,-11317700,7240931,-237388 },
+ },
+ {
+  { -31361739,-11346780,-15007447,-5856218,-22453340,-12152771,1222336,4389483,3293637,-15551743 },
+  { -16684801,-14444245,11038544,11054958,-13801175,-3338533,-24319580,7733547,12796905,-6335822 },
+  { -8759414,-10817836,-25418864,10783769,-30615557,-9746811,-28253339,3647836,3222231,-11160462 },
+ },
+ {
+  { 18606113,1693100,-25448386,-15170272,4112353,10045021,23603893,-2048234,-7550776,2484985 },
+  { 9255317,-3131197,-12156162,-1004256,13098013,-9214866,16377220,-2102812,-19802075,-3034702 },
+  { -22729289,7496160,-5742199,11329249,19991973,-3347502,-31718148,9936966,-30097688,-10618797 },
+ },
+ {
+  { 21878590,-5001297,4338336,13643897,-3036865,13160960,19708896,5415497,-7360503,-4109293 },
+  { 27736861,10103576,12500508,8502413,-3413016,-9633558,10436918,-1550276,-23659143,-8132100 },
+  { 19492550,-12104365,-29681976,-852630,-3208171,12403437,30066266,8367329,13243957,8709688 },
+ },
+},
+{
+ {
+  { 12015105,2801261,28198131,10151021,24818120,-4743133,-11194191,-5645734,5150968,7274186 },
+  { 2831366,-12492146,1478975,6122054,23825128,-12733586,31097299,6083058,31021603,-9793610 },
+  { -2529932,-2229646,445613,10720828,-13849527,-11505937,-23507731,16354465,15067285,-14147707 },
+ },
+ {
+  { 7840942,14037873,-33364863,15934016,-728213,-3642706,21403988,1057586,-19379462,-12403220 },
+  { 915865,-16469274,15608285,-8789130,-24357026,6060030,-17371319,8410997,-7220461,16527025 },
+  { 32922597,-556987,20336074,-16184568,10903705,-5384487,16957574,52992,23834301,6588044 },
+ },
+ {
+  { 32752030,11232950,3381995,-8714866,22652988,-10744103,17159699,16689107,-20314580,-1305992 },
+  { -4689649,9166776,-25710296,-10847306,11576752,12733943,7924251,-2752281,1976123,-7249027 },
+  { 21251222,16309901,-2983015,-6783122,30810597,12967303,156041,-3371252,12331345,-8237197 },
+ },
+ {
+  { 8651614,-4477032,-16085636,-4996994,13002507,2950805,29054427,-5106970,10008136,-4667901 },
+  { 31486080,15114593,-14261250,12951354,14369431,-7387845,16347321,-13662089,8684155,-10532952 },
+  { 19443825,11385320,24468943,-9659068,-23919258,2187569,-26263207,-6086921,31316348,14219878 },
+ },
+ {
+  { -28594490,1193785,32245219,11392485,31092169,15722801,27146014,6992409,29126555,9207390 },
+  { 32382935,1110093,18477781,11028262,-27411763,-7548111,-4980517,10843782,-7957600,-14435730 },
+  { 2814918,7836403,27519878,-7868156,-20894015,-11553689,-21494559,8550130,28346258,1994730 },
+ },
+ {
+  { -19578299,8085545,-14000519,-3948622,2785838,-16231307,-19516951,7174894,22628102,8115180 },
+  { -30405132,955511,-11133838,-15078069,-32447087,-13278079,-25651578,3317160,-9943017,930272 },
+  { -15303681,-6833769,28856490,1357446,23421993,1057177,24091212,-1388970,-22765376,-10650715 },
+ },
+ {
+  { -22751231,-5303997,-12907607,-12768866,-15811511,-7797053,-14839018,-16554220,-1867018,8398970 },
+  { -31969310,2106403,-4736360,1362501,12813763,16200670,22981545,-6291273,18009408,-15772772 },
+  { -17220923,-9545221,-27784654,14166835,29815394,7444469,29551787,-3727419,19288549,1325865 },
+ },
+ {
+  { 15100157,-15835752,-23923978,-1005098,-26450192,15509408,12376730,-3479146,33166107,-8042750 },
+  { 20909231,13023121,-9209752,16251778,-5778415,-8094914,12412151,10018715,2213263,-13878373 },
+  { 32529814,-11074689,30361439,-16689753,-9135940,1513226,22922121,6382134,-5766928,8371348 },
+ },
+},
+{
+ {
+  { 9923462,11271500,12616794,3544722,-29998368,-1721626,12891687,-8193132,-26442943,10486144 },
+  { -22597207,-7012665,8587003,-8257861,4084309,-12970062,361726,2610596,-23921530,-11455195 },
+  { 5408411,-1136691,-4969122,10561668,24145918,14240566,31319731,-4235541,19985175,-3436086 },
+ },
+ {
+  { -13994457,16616821,14549246,3341099,32155958,13648976,-17577068,8849297,65030,8370684 },
+  { -8320926,-12049626,31204563,5839400,-20627288,-1057277,-19442942,6922164,12743482,-9800518 },
+  { -2361371,12678785,28815050,4759974,-23893047,4884717,23783145,11038569,18800704,255233 },
+ },
+ {
+  { -5269658,-1773886,13957886,7990715,23132995,728773,13393847,9066957,19258688,-14753793 },
+  { -2936654,-10827535,-10432089,14516793,-3640786,4372541,-31934921,2209390,-1524053,2055794 },
+  { 580882,16705327,5468415,-2683018,-30926419,-14696000,-7203346,-8994389,-30021019,7394435 },
+ },
+ {
+  { 23838809,1822728,-15738443,15242727,8318092,-3733104,-21672180,-3492205,-4821741,14799921 },
+  { 13345610,9759151,3371034,-16137791,16353039,8577942,31129804,13496856,-9056018,7402518 },
+  { 2286874,-4435931,-20042458,-2008336,-13696227,5038122,11006906,-15760352,8205061,1607563 },
+ },
+ {
+  { 14414086,-8002132,3331830,-3208217,22249151,-5594188,18364661,-2906958,30019587,-9029278 },
+  { -27688051,1585953,-10775053,931069,-29120221,-11002319,-14410829,12029093,9944378,8024 },
+  { 4368715,-3709630,29874200,-15022983,-20230386,-11410704,-16114594,-999085,-8142388,5640030 },
+ },
+ {
+  { 10299610,13746483,11661824,16234854,7630238,5998374,9809887,-16694564,15219798,-14327783 },
+  { 27425505,-5719081,3055006,10660664,23458024,595578,-15398605,-1173195,-18342183,9742717 },
+  { 6744077,2427284,26042789,2720740,-847906,1118974,32324614,7406442,12420155,1994844 },
+ },
+ {
+  { 14012521,-5024720,-18384453,-9578469,-26485342,-3936439,-13033478,-10909803,24319929,-6446333 },
+  { 16412690,-4507367,10772641,15929391,-17068788,-4658621,10555945,-10484049,-30102368,-4739048 },
+  { 22397382,-7767684,-9293161,-12792868,17166287,-9755136,-27333065,6199366,21880021,-12250760 },
+ },
+ {
+  { -4283307,5368523,-31117018,8163389,-30323063,3209128,16557151,8890729,8840445,4957760 },
+  { -15447727,709327,-6919446,-10870178,-29777922,6522332,-21720181,12130072,-14796503,5005757 },
+  { -2114751,-14308128,23019042,15765735,-25269683,6002752,10183197,-13239326,-16395286,-2176112 },
+ },
+},
+{
+ {
+  { -19025756,1632005,13466291,-7995100,-23640451,16573537,-32013908,-3057104,22208662,2000468 },
+  { 3065073,-1412761,-25598674,-361432,-17683065,-5703415,-8164212,11248527,-3691214,-7414184 },
+  { 10379208,-6045554,8877319,1473647,-29291284,-12507580,16690915,2553332,-3132688,16400289 },
+ },
+ {
+  { 15716668,1254266,-18472690,7446274,-8448918,6344164,-22097271,-7285580,26894937,9132066 },
+  { 24158887,12938817,11085297,-8177598,-28063478,-4457083,-30576463,64452,-6817084,-2692882 },
+  { 13488534,7794716,22236231,5989356,25426474,-12578208,2350710,-3418511,-4688006,2364226 },
+ },
+ {
+  { 16335052,9132434,25640582,6678888,1725628,8517937,-11807024,-11697457,15445875,-7798101 },
+  { 29004207,-7867081,28661402,-640412,-12794003,-7943086,31863255,-4135540,-278050,-15759279 },
+  { -6122061,-14866665,-28614905,14569919,-10857999,-3591829,10343412,-6976290,-29828287,-10815811 },
+ },
+ {
+  { 27081650,3463984,14099042,-4517604,1616303,-6205604,29542636,15372179,17293797,960709 },
+  { 20263915,11434237,-5765435,11236810,13505955,-10857102,-16111345,6493122,-19384511,7639714 },
+  { -2830798,-14839232,25403038,-8215196,-8317012,-16173699,18006287,-16043750,29994677,-15808121 },
+ },
+ {
+  { 9769828,5202651,-24157398,-13631392,-28051003,-11561624,-24613141,-13860782,-31184575,709464 },
+  { 12286395,13076066,-21775189,-1176622,-25003198,4057652,-32018128,-8890874,16102007,13205847 },
+  { 13733362,5599946,10557076,3195751,-5557991,8536970,-25540170,8525972,10151379,10394400 },
+ },
+ {
+  { 4024660,-16137551,22436262,12276534,-9099015,-2686099,19698229,11743039,-33302334,8934414 },
+  { -15879800,-4525240,-8580747,-2934061,14634845,-698278,-9449077,3137094,-11536886,11721158 },
+  { 17555939,-5013938,8268606,2331751,-22738815,9761013,9319229,8835153,-9205489,-1280045 },
+ },
+ {
+  { -461409,-7830014,20614118,16688288,-7514766,-4807119,22300304,505429,6108462,-6183415 },
+  { -5070281,12367917,-30663534,3234473,32617080,-8422642,29880583,-13483331,-26898490,-7867459 },
+  { -31975283,5726539,26934134,10237677,-3173717,-605053,24199304,3795095,7592688,-14992079 },
+ },
+ {
+  { 21594432,-14964228,17466408,-4077222,32537084,2739898,6407723,12018833,-28256052,4298412 },
+  { -20650503,-11961496,-27236275,570498,3767144,-1717540,13891942,-1569194,13717174,10805743 },
+  { -14676630,-15644296,15287174,11927123,24177847,-8175568,-796431,14860609,-26938930,-5863836 },
+ },
+},
+{
+ {
+  { 12962541,5311799,-10060768,11658280,18855286,-7954201,13286263,-12808704,-4381056,9882022 },
+  { 18512079,11319350,-20123124,15090309,18818594,5271736,-22727904,3666879,-23967430,-3299429 },
+  { -6789020,-3146043,16192429,13241070,15898607,-14206114,-10084880,-6661110,-2403099,5276065 },
+ },
+ {
+  { 30169808,-5317648,26306206,-11750859,27814964,7069267,7152851,3684982,1449224,13082861 },
+  { 10342826,3098505,2119311,193222,25702612,12233820,23697382,15056736,-21016438,-8202000 },
+  { -33150110,3261608,22745853,7948688,19370557,-15177665,-26171976,6482814,-10300080,-11060101 },
+ },
+ {
+  { 32869458,-5408545,25609743,15678670,-10687769,-15471071,26112421,2521008,-22664288,6904815 },
+  { 29506923,4457497,3377935,-9796444,-30510046,12935080,1561737,3841096,-29003639,-6657642 },
+  { 10340844,-6630377,-18656632,-2278430,12621151,-13339055,30878497,-11824370,-25584551,5181966 },
+ },
+ {
+  { 25940115,-12658025,17324188,-10307374,-8671468,15029094,24396252,-16450922,-2322852,-12388574 },
+  { -21765684,9916823,-1300409,4079498,-1028346,11909559,1782390,12641087,20603771,-6561742 },
+  { -18882287,-11673380,24849422,11501709,13161720,-4768874,1925523,11914390,4662781,7820689 },
+ },
+ {
+  { 12241050,-425982,8132691,9393934,32846760,-1599620,29749456,12172924,16136752,15264020 },
+  { -10349955,-14680563,-8211979,2330220,-17662549,-14545780,10658213,6671822,19012087,3772772 },
+  { 3753511,-3421066,10617074,2028709,14841030,-6721664,28718732,-15762884,20527771,12988982 },
+ },
+ {
+  { -14822485,-5797269,-3707987,12689773,-898983,-10914866,-24183046,-10564943,3299665,-12424953 },
+  { -16777703,-15253301,-9642417,4978983,3308785,8755439,6943197,6461331,-25583147,8991218 },
+  { -17226263,1816362,-1673288,-6086439,31783888,-8175991,-32948145,7417950,-30242287,1507265 },
+ },
+ {
+  { 29692663,6829891,-10498800,4334896,20945975,-11906496,-28887608,8209391,14606362,-10647073 },
+  { -3481570,8707081,32188102,5672294,22096700,1711240,-33020695,9761487,4170404,-2085325 },
+  { -11587470,14855945,-4127778,-1531857,-26649089,15084046,22186522,16002000,-14276837,-8400798 },
+ },
+ {
+  { -4811456,13761029,-31703877,-2483919,-3312471,7869047,-7113572,-9620092,13240845,10965870 },
+  { -7742563,-8256762,-14768334,-13656260,-23232383,12387166,4498947,14147411,29514390,4302863 },
+  { -13413405,-12407859,20757302,-13801832,14785143,8976368,-5061276,-2144373,17846988,-13971927 },
+ },
+},
+{
+ {
+  { -2244452,-754728,-4597030,-1066309,-6247172,1455299,-21647728,-9214789,-5222701,12650267 },
+  { -9906797,-16070310,21134160,12198166,-27064575,708126,387813,13770293,-19134326,10958663 },
+  { 22470984,12369526,23446014,-5441109,-21520802,-9698723,-11772496,-11574455,-25083830,4271862 },
+ },
+ {
+  { -25169565,-10053642,-19909332,15361595,-5984358,2159192,75375,-4278529,-32526221,8469673 },
+  { 15854970,4148314,-8893890,7259002,11666551,13824734,-30531198,2697372,24154791,-9460943 },
+  { 15446137,-15806644,29759747,14019369,30811221,-9610191,-31582008,12840104,24913809,9815020 },
+ },
+ {
+  { -4709286,-5614269,-31841498,-12288893,-14443537,10799414,-9103676,13438769,18735128,9466238 },
+  { 11933045,9281483,5081055,-5183824,-2628162,-4905629,-7727821,-10896103,-22728655,16199064 },
+  { 14576810,379472,-26786533,-8317236,-29426508,-10812974,-102766,1876699,30801119,2164795 },
+ },
+ {
+  { 15995086,3199873,13672555,13712240,-19378835,-4647646,-13081610,-15496269,-13492807,1268052 },
+  { -10290614,-3659039,-3286592,10948818,23037027,3794475,-3470338,-12600221,-17055369,3565904 },
+  { 29210088,-9419337,-5919792,-4952785,10834811,-13327726,-16512102,-10820713,-27162222,-14030531 },
+ },
+ {
+  { -13161890,15508588,16663704,-8156150,-28349942,9019123,-29183421,-3769423,2244111,-14001979 },
+  { -5152875,-3800936,-9306475,-6071583,16243069,14684434,-25673088,-16180800,13491506,4641841 },
+  { 10813417,643330,-19188515,-728916,30292062,-16600078,27548447,-7721242,14476989,-12767431 },
+ },
+ {
+  { 10292079,9984945,6481436,8279905,-7251514,7032743,27282937,-1644259,-27912810,12651324 },
+  { -31185513,-813383,22271204,11835308,10201545,15351028,17099662,3988035,21721536,-3148940 },
+  { 10202177,-6545839,-31373232,-9574638,-32150642,-8119683,-12906320,3852694,13216206,14842320 },
+ },
+ {
+  { -15815640,-10601066,-6538952,-7258995,-6984659,-6581778,-31500847,13765824,-27434397,9900184 },
+  { 14465505,-13833331,-32133984,-14738873,-27443187,12990492,33046193,15796406,-7051866,-8040114 },
+  { 30924417,-8279620,6359016,-12816335,16508377,9071735,-25488601,15413635,9524356,-7018878 },
+ },
+ {
+  { 12274201,-13175547,32627641,-1785326,6736625,13267305,5237659,-5109483,15663516,4035784 },
+  { -2951309,8903985,17349946,601635,-16432815,-4612556,-13732739,-15889334,-22258478,4659091 },
+  { -16916263,-4952973,-30393711,-15158821,20774812,15897498,5736189,15026997,-2178256,-13455585 },
+ },
+},
+{
+ {
+  { -8858980,-2219056,28571666,-10155518,-474467,-10105698,-3801496,278095,23440562,-290208 },
+  { 10226241,-5928702,15139956,120818,-14867693,5218603,32937275,11551483,-16571960,-7442864 },
+  { 17932739,-12437276,-24039557,10749060,11316803,7535897,22503767,5561594,-3646624,3898661 },
+ },
+ {
+  { 7749907,-969567,-16339731,-16464,-25018111,15122143,-1573531,7152530,21831162,1245233 },
+  { 26958459,-14658026,4314586,8346991,-5677764,11960072,-32589295,-620035,-30402091,-16716212 },
+  { -12165896,9166947,33491384,13673479,29787085,13096535,6280834,14587357,-22338025,13987525 },
+ },
+ {
+  { -24349909,7778775,21116000,15572597,-4833266,-5357778,-4300898,-5124639,-7469781,-2858068 },
+  { 9681908,-6737123,-31951644,13591838,-6883821,386950,31622781,6439245,-14581012,4091397 },
+  { -8426427,1470727,-28109679,-1596990,3978627,-5123623,-19622683,12092163,29077877,-14741988 },
+ },
+ {
+  { 5269168,-6859726,-13230211,-8020715,25932563,1763552,-5606110,-5505881,-20017847,2357889 },
+  { 32264008,-15407652,-5387735,-1160093,-2091322,-3946900,23104804,-12869908,5727338,189038 },
+  { 14609123,-8954470,-6000566,-16622781,-14577387,-7743898,-26745169,10942115,-25888931,-14884697 },
+ },
+ {
+  { 20513500,5557931,-15604613,7829531,26413943,-2019404,-21378968,7471781,13913677,-5137875 },
+  { -25574376,11967826,29233242,12948236,-6754465,4713227,-8940970,14059180,12878652,8511905 },
+  { -25656801,3393631,-2955415,-7075526,-2250709,9366908,-30223418,6812974,5568676,-3127656 },
+ },
+ {
+  { 11630004,12144454,2116339,13606037,27378885,15676917,-17408753,-13504373,-14395196,8070818 },
+  { 27117696,-10007378,-31282771,-5570088,1127282,12772488,-29845906,10483306,-11552749,-1028714 },
+  { 10637467,-5688064,5674781,1072708,-26343588,-6982302,-1683975,9177853,-27493162,15431203 },
+ },
+ {
+  { 20525145,10892566,-12742472,12779443,-29493034,16150075,-28240519,14943142,-15056790,-7935931 },
+  { -30024462,5626926,-551567,-9981087,753598,11981191,25244767,-3239766,-3356550,9594024 },
+  { -23752644,2636870,-5163910,-10103818,585134,7877383,11345683,-6492290,13352335,-10977084 },
+ },
+ {
+  { -1931799,-5407458,3304649,-12884869,17015806,-4877091,-29783850,-7752482,-13215537,-319204 },
+  { 20239939,6607058,6203985,3483793,-18386976,-779229,-20723742,15077870,-22750759,14523817 },
+  { 27406042,-6041657,27423596,-4497394,4996214,10002360,-28842031,-4545494,-30172742,-4805667 },
+ },
+},
+{
+ {
+  { 11374242,12660715,17861383,-12540833,10935568,1099227,-13886076,-9091740,-27727044,11358504 },
+  { -12730809,10311867,1510375,10778093,-2119455,-9145702,32676003,11149336,-26123651,4985768 },
+  { -19096303,341147,-6197485,-239033,15756973,-8796662,-983043,13794114,-19414307,-15621255 },
+ },
+ {
+  { 6490081,11940286,25495923,-7726360,8668373,-8751316,3367603,6970005,-1691065,-9004790 },
+  { 1656497,13457317,15370807,6364910,13605745,8362338,-19174622,-5475723,-16796596,-5031438 },
+  { -22273315,-13524424,-64685,-4334223,-18605636,-10921968,-20571065,-7007978,-99853,-10237333 },
+ },
+ {
+  { 17747465,10039260,19368299,-4050591,-20630635,-16041286,31992683,-15857976,-29260363,-5511971 },
+  { 31932027,-4986141,-19612382,16366580,22023614,88450,11371999,-3744247,4882242,-10626905 },
+  { 29796507,37186,19818052,10115756,-11829032,3352736,18551198,3272828,-5190932,-4162409 },
+ },
+ {
+  { 12501286,4044383,-8612957,-13392385,-32430052,5136599,-19230378,-3529697,330070,-3659409 },
+  { 6384877,2899513,17807477,7663917,-2358888,12363165,25366522,-8573892,-271295,12071499 },
+  { -8365515,-4042521,25133448,-4517355,-6211027,2265927,-32769618,1936675,-5159697,3829363 },
+ },
+ {
+  { 28425966,-5835433,-577090,-4697198,-14217555,6870930,7921550,-6567787,26333140,14267664 },
+  { -11067219,11871231,27385719,-10559544,-4585914,-11189312,10004786,-8709488,-21761224,8930324 },
+  { -21197785,-16396035,25654216,-1725397,12282012,11008919,1541940,4757911,-26491501,-16408940 },
+ },
+ {
+  { 13537262,-7759490,-20604840,10961927,-5922820,-13218065,-13156584,6217254,-15943699,13814990 },
+  { -17422573,15157790,18705543,29619,24409717,-260476,27361681,9257833,-1956526,-1776914 },
+  { -25045300,-10191966,15366585,15166509,-13105086,8423556,-29171540,12361135,-18685978,4578290 },
+ },
+ {
+  { 24579768,3711570,1342322,-11180126,-27005135,14124956,-22544529,14074919,21964432,8235257 },
+  { -6528613,-2411497,9442966,-5925588,12025640,-1487420,-2981514,-1669206,13006806,2355433 },
+  { -16304899,-13605259,-6632427,-5142349,16974359,-10911083,27202044,1719366,1141648,-12796236 },
+ },
+ {
+  { -12863944,-13219986,-8318266,-11018091,-6810145,-4843894,13475066,-3133972,32674895,13715045 },
+  { 11423335,-5468059,32344216,8962751,24989809,9241752,-13265253,16086212,-28740881,-15642093 },
+  { -1409668,12530728,-6368726,10847387,19531186,-14132160,-11709148,7791794,-27245943,4383347 },
+ },
+},
+{
+ {
+  { -28970898,5271447,-1266009,-9736989,-12455236,16732599,-4862407,-4906449,27193557,6245191 },
+  { -15193956,5362278,-1783893,2695834,4960227,12840725,23061898,3260492,22510453,8577507 },
+  { -12632451,11257346,-32692994,13548177,-721004,10879011,31168030,13952092,-29571492,-3635906 },
+ },
+ {
+  { 3877321,-9572739,32416692,5405324,-11004407,-13656635,3759769,11935320,5611860,8164018 },
+  { -16275802,14667797,15906460,12155291,-22111149,-9039718,32003002,-8832289,5773085,-8422109 },
+  { -23788118,-8254300,1950875,8937633,18686727,16459170,-905725,12376320,31632953,190926 },
+ },
+ {
+  { -24593607,-16138885,-8423991,13378746,14162407,6901328,-8288749,4508564,-25341555,-3627528 },
+  { 8884438,-5884009,6023974,10104341,-6881569,-4941533,18722941,-14786005,-1672488,827625 },
+  { -32720583,-16289296,-32503547,7101210,13354605,2659080,-1800575,-14108036,-24878478,1541286 },
+ },
+ {
+  { 2901347,-1117687,3880376,-10059388,-17620940,-3612781,-21802117,-3567481,20456845,-1885033 },
+  { 27019610,12299467,-13658288,-1603234,-12861660,-4861471,-19540150,-5016058,29439641,15138866 },
+  { 21536104,-6626420,-32447818,-10690208,-22408077,5175814,-5420040,-16361163,7779328,109896 },
+ },
+ {
+  { 30279744,14648750,-8044871,6425558,13639621,-743509,28698390,12180118,23177719,-554075 },
+  { 26572847,3405927,-31701700,12890905,-19265668,5335866,-6493768,2378492,4439158,-13279347 },
+  { -22716706,3489070,-9225266,-332753,18875722,-1140095,14819434,-12731527,-17717757,-5461437 },
+ },
+ {
+  { -5056483,16566551,15953661,3767752,-10436499,15627060,-820954,2177225,8550082,-15114165 },
+  { -18473302,16596775,-381660,15663611,22860960,15585581,-27844109,-3582739,-23260460,-8428588 },
+  { -32480551,15707275,-8205912,-5652081,29464558,2713815,-22725137,15860482,-21902570,1494193 },
+ },
+ {
+  { -19562091,-14087393,-25583872,-9299552,13127842,759709,21923482,16529112,8742704,12967017 },
+  { -28464899,1553205,32536856,-10473729,-24691605,-406174,-8914625,-2933896,-29903758,15553883 },
+  { 21877909,3230008,9881174,10539357,-4797115,2841332,11543572,14513274,19375923,-12647961 },
+ },
+ {
+  { 8832269,-14495485,13253511,5137575,5037871,4078777,24880818,-6222716,2862653,9455043 },
+  { 29306751,5123106,20245049,-14149889,9592566,8447059,-2077124,-2990080,15511449,4789663 },
+  { -20679756,7004547,8824831,-9434977,-4045704,-3750736,-5754762,108893,23513200,16652362 },
+ },
+},
+{
+ {
+  { -33256173,4144782,-4476029,-6579123,10770039,-7155542,-6650416,-12936300,-18319198,10212860 },
+  { 2756081,8598110,7383731,-6859892,22312759,-1105012,21179801,2600940,-9988298,-12506466 },
+  { -24645692,13317462,-30449259,-15653928,21365574,-10869657,11344424,864440,-2499677,-16710063 },
+ },
+ {
+  { -26432803,6148329,-17184412,-14474154,18782929,-275997,-22561534,211300,2719757,4940997 },
+  { -1323882,3911313,-6948744,14759765,-30027150,7851207,21690126,8518463,26699843,5276295 },
+  { -13149873,-6429067,9396249,365013,24703301,-10488939,1321586,149635,-15452774,7159369 },
+ },
+ {
+  { 9987780,-3404759,17507962,9505530,9731535,-2165514,22356009,8312176,22477218,-8403385 },
+  { 18155857,-16504990,19744716,9006923,15154154,-10538976,24256460,-4864995,-22548173,9334109 },
+  { 2986088,-4911893,10776628,-3473844,10620590,-7083203,-21413845,14253545,-22587149,536906 },
+ },
+ {
+  { 4377756,8115836,24567078,15495314,11625074,13064599,7390551,10589625,10838060,-15420424 },
+  { -19342404,867880,9277171,-3218459,-14431572,-1986443,19295826,-15796950,6378260,699185 },
+  { 7895026,4057113,-7081772,-13077756,-17886831,-323126,-716039,15693155,-5045064,-13373962 },
+ },
+ {
+  { -7737563,-5869402,-14566319,-7406919,11385654,13201616,31730678,-10962840,-3918636,-9669325 },
+  { 10188286,-15770834,-7336361,13427543,22223443,14896287,30743455,7116568,-21786507,5427593 },
+  { 696102,13206899,27047647,-10632082,15285305,-9853179,10798490,-4578720,19236243,12477404 },
+ },
+ {
+  { -11229439,11243796,-17054270,-8040865,-788228,-8167967,-3897669,11180504,-23169516,7733644 },
+  { 17800790,-14036179,-27000429,-11766671,23887827,3149671,23466177,-10538171,10322027,15313801 },
+  { 26246234,11968874,32263343,-5468728,6830755,-13323031,-15794704,-101982,-24449242,10890804 },
+ },
+ {
+  { -31365647,10271363,-12660625,-6267268,16690207,-13062544,-14982212,16484931,25180797,-5334884 },
+  { -586574,10376444,-32586414,-11286356,19801893,10997610,2276632,9482883,316878,13820577 },
+  { -9882808,-4510367,-2115506,16457136,-11100081,11674996,30756178,-7515054,30696930,-3712849 },
+ },
+ {
+  { 32988917,-9603412,12499366,7910787,-10617257,-11931514,-7342816,-9985397,-32349517,7392473 },
+  { -8855661,15927861,9866406,-3649411,-2396914,-16655781,-30409476,-9134995,25112947,-2926644 },
+  { -2504044,-436966,25621774,-5678772,15085042,-5479877,-24884878,-13526194,5537438,-13914319 },
+ },
+},
+{
+ {
+  { -11225584,2320285,-9584280,10149187,-33444663,5808648,-14876251,-1729667,31234590,6090599 },
+  { -9633316,116426,26083934,2897444,-6364437,-2688086,609721,15878753,-6970405,-9034768 },
+  { -27757857,247744,-15194774,-9002551,23288161,-10011936,-23869595,6503646,20650474,1804084 },
+ },
+ {
+  { -27589786,15456424,8972517,8469608,15640622,4439847,3121995,-10329713,27842616,-202328 },
+  { -15306973,2839644,22530074,10026331,4602058,5048462,28248656,5031932,-11375082,12714369 },
+  { 20807691,-7270825,29286141,11421711,-27876523,-13868230,-21227475,1035546,-19733229,12796920 },
+ },
+ {
+  { 12076899,-14301286,-8785001,-11848922,-25012791,16400684,-17591495,-12899438,3480665,-15182815 },
+  { -32361549,5457597,28548107,7833186,7303070,-11953545,-24363064,-15921875,-33374054,2771025 },
+  { -21389266,421932,26597266,6860826,22486084,-6737172,-17137485,-4210226,-24552282,15673397 },
+ },
+ {
+  { -20184622,2338216,19788685,-9620956,-4001265,-8740893,-20271184,4733254,3727144,-12934448 },
+  { 6120119,814863,-11794402,-622716,6812205,-15747771,2019594,7975683,31123697,-10958981 },
+  { 30069250,-11435332,30434654,2958439,18399564,-976289,12296869,9204260,-16432438,9648165 },
+ },
+ {
+  { 32705432,-1550977,30705658,7451065,-11805606,9631813,3305266,5248604,-26008332,-11377501 },
+  { 17219865,2375039,-31570947,-5575615,-19459679,9219903,294711,15298639,2662509,-16297073 },
+  { -1172927,-7558695,-4366770,-4287744,-21346413,-8434326,32087529,-1222777,32247248,-14389861 },
+ },
+ {
+  { 14312628,1221556,17395390,-8700143,-4945741,-8684635,-28197744,-9637817,-16027623,-13378845 },
+  { -1428825,-9678990,-9235681,6549687,-7383069,-468664,23046502,9803137,17597934,2346211 },
+  { 18510800,15337574,26171504,981392,-22241552,7827556,-23491134,-11323352,3059833,-11782870 },
+ },
+ {
+  { 10141598,6082907,17829293,-1947643,9830092,13613136,-25556636,-5544586,-33502212,3592096 },
+  { 33114168,-15889352,-26525686,-13343397,33076705,8716171,1151462,1521897,-982665,-6837803 },
+  { -32939165,-4255815,23947181,-324178,-33072974,-12305637,-16637686,3891704,26353178,693168 },
+ },
+ {
+  { 30374239,1595580,-16884039,13186931,4600344,406904,9585294,-400668,31375464,14369965 },
+  { -14370654,-7772529,1510301,6434173,-18784789,-6262728,32732230,-13108839,17901441,16011505 },
+  { 18171223,-11934626,-12500402,15197122,-11038147,-15230035,-19172240,-16046376,8764035,12309598 },
+ },
+},
+{
+ {
+  { 5975908,-5243188,-19459362,-9681747,-11541277,14015782,-23665757,1228319,17544096,-10593782 },
+  { 5811932,-1715293,3442887,-2269310,-18367348,-8359541,-18044043,-15410127,-5565381,12348900 },
+  { -31399660,11407555,25755363,6891399,-3256938,14872274,-24849353,8141295,-10632534,-585479 },
+ },
+ {
+  { -12675304,694026,-5076145,13300344,14015258,-14451394,-9698672,-11329050,30944593,1130208 },
+  { 8247766,-6710942,-26562381,-7709309,-14401939,-14648910,4652152,2488540,23550156,-271232 },
+  { 17294316,-3788438,7026748,15626851,22990044,113481,2267737,-5908146,-408818,-137719 },
+ },
+ {
+  { 16091085,-16253926,18599252,7340678,2137637,-1221657,-3364161,14550936,3260525,-7166271 },
+  { -4910104,-13332887,18550887,10864893,-16459325,-7291596,-23028869,-13204905,-12748722,2701326 },
+  { -8574695,16099415,4629974,-16340524,-20786213,-6005432,-10018363,9276971,11329923,1862132 },
+ },
+ {
+  { 14763076,-15903608,-30918270,3689867,3511892,10313526,-21951088,12219231,-9037963,-940300 },
+  { 8894987,-3446094,6150753,3013931,301220,15693451,-31981216,-2909717,-15438168,11595570 },
+  { 15214962,3537601,-26238722,-14058872,4418657,-15230761,13947276,10730794,-13489462,-4363670 },
+ },
+ {
+  { -2538306,7682793,32759013,263109,-29984731,-7955452,-22332124,-10188635,977108,699994 },
+  { -12466472,4195084,-9211532,550904,-15565337,12917920,19118110,-439841,-30534533,-14337913 },
+  { 31788461,-14507657,4799989,7372237,8808585,-14747943,9408237,-10051775,12493932,-5409317 },
+ },
+ {
+  { -25680606,5260744,-19235809,-6284470,-3695942,16566087,27218280,2607121,29375955,6024730 },
+  { 842132,-2794693,-4763381,-8722815,26332018,-12405641,11831880,6985184,-9940361,2854096 },
+  { -4847262,-7969331,2516242,-5847713,9695691,-7221186,16512645,960770,12121869,16648078 },
+ },
+ {
+  { -15218652,14667096,-13336229,2013717,30598287,-464137,-31504922,-7882064,20237806,2838411 },
+  { -19288047,4453152,15298546,-16178388,22115043,-15972604,12544294,-13470457,1068881,-12499905 },
+  { -9558883,-16518835,33238498,13506958,30505848,-1114596,-8486907,-2630053,12521378,4845654 },
+ },
+ {
+  { -28198521,10744108,-2958380,10199664,7759311,-13088600,3409348,-873400,-6482306,-12885870 },
+  { -23561822,6230156,-20382013,10655314,-24040585,-11621172,10477734,-1240216,-3113227,13974498 },
+  { 12966261,15550616,-32038948,-1615346,21025980,-629444,5642325,7188737,18895762,12629579 },
+ },
+},
+{
+ {
+  { 14741879,-14946887,22177208,-11721237,1279741,8058600,11758140,789443,32195181,3895677 },
+  { 10758205,15755439,-4509950,9243698,-4879422,6879879,-2204575,-3566119,-8982069,4429647 },
+  { -2453894,15725973,-20436342,-10410672,-5803908,-11040220,-7135870,-11642895,18047436,-15281743 },
+ },
+ {
+  { -25173001,-11307165,29759956,11776784,-22262383,-15820455,10993114,-12850837,-17620701,-9408468 },
+  { 21987233,700364,-24505048,14972008,-7774265,-5718395,32155026,2581431,-29958985,8773375 },
+  { -25568350,454463,-13211935,16126715,25240068,8594567,20656846,12017935,-7874389,-13920155 },
+ },
+ {
+  { 6028182,6263078,-31011806,-11301710,-818919,2461772,-31841174,-5468042,-1721788,-2776725 },
+  { -12278994,16624277,987579,-5922598,32908203,1248608,7719845,-4166698,28408820,6816612 },
+  { -10358094,-8237829,19549651,-12169222,22082623,16147817,20613181,13982702,-10339570,5067943 },
+ },
+ {
+  { -30505967,-3821767,12074681,13582412,-19877972,2443951,-19719286,12746132,5331210,-10105944 },
+  { 30528811,3601899,-1957090,4619785,-27361822,-15436388,24180793,-12570394,27679908,-1648928 },
+  { 9402404,-13957065,32834043,10838634,-26580150,-13237195,26653274,-8685565,22611444,-12715406 },
+ },
+ {
+  { 22190590,1118029,22736441,15130463,-30460692,-5991321,19189625,-4648942,4854859,6622139 },
+  { -8310738,-2953450,-8262579,-3388049,-10401731,-271929,13424426,-3567227,26404409,13001963 },
+  { -31241838,-15415700,-2994250,8939346,11562230,-12840670,-26064365,-11621720,-15405155,11020693 },
+ },
+ {
+  { 1866042,-7949489,-7898649,-10301010,12483315,13477547,3175636,-12424163,28761762,1406734 },
+  { -448555,-1777666,13018551,3194501,-9580420,-11161737,24760585,-4347088,25577411,-13378680 },
+  { -24290378,4759345,-690653,-1852816,2066747,10693769,-29595790,9884936,-9368926,4745410 },
+ },
+ {
+  { -9141284,6049714,-19531061,-4341411,-31260798,9944276,-15462008,-11311852,10931924,-11931931 },
+  { -16561513,14112680,-8012645,4817318,-8040464,-11414606,-22853429,10856641,-20470770,13434654 },
+  { 22759489,-10073434,-16766264,-1871422,13637442,-10168091,1765144,-12654326,28445307,-5364710 },
+ },
+ {
+  { 29875063,12493613,2795536,-3786330,1710620,15181182,-10195717,-8788675,9074234,1167180 },
+  { -26205683,11014233,-9842651,-2635485,-26908120,7532294,-18716888,-9535498,3843903,9367684 },
+  { -10969595,-6403711,9591134,9582310,11349256,108879,16235123,8601684,-139197,4242895 },
+ },
+},
+{
+ {
+  { 22092954,-13191123,-2042793,-11968512,32186753,-11517388,-6574341,2470660,-27417366,16625501 },
+  { -11057722,3042016,13770083,-9257922,584236,-544855,-7770857,2602725,-27351616,14247413 },
+  { 6314175,-10264892,-32772502,15957557,-10157730,168750,-8618807,14290061,27108877,-1180880 },
+ },
+ {
+  { -8586597,-7170966,13241782,10960156,-32991015,-13794596,33547976,-11058889,-27148451,981874 },
+  { 22833440,9293594,-32649448,-13618667,-9136966,14756819,-22928859,-13970780,-10479804,-16197962 },
+  { -7768587,3326786,-28111797,10783824,19178761,14905060,22680049,13906969,-15933690,3797899 },
+ },
+ {
+  { 21721356,-4212746,-12206123,9310182,-3882239,-13653110,23740224,-2709232,20491983,-8042152 },
+  { 9209270,-15135055,-13256557,-6167798,-731016,15289673,25947805,15286587,30997318,-6703063 },
+  { 7392032,16618386,23946583,-8039892,-13265164,-1533858,-14197445,-2321576,17649998,-250080 },
+ },
+ {
+  { -9301088,-14193827,30609526,-3049543,-25175069,-1283752,-15241566,-9525724,-2233253,7662146 },
+  { -17558673,1763594,-33114336,15908610,-30040870,-12174295,7335080,-8472199,-3174674,3440183 },
+  { -19889700,-5977008,-24111293,-9688870,10799743,-16571957,40450,-4431835,4862400,1133 },
+ },
+ {
+  { -32856209,-7873957,-5422389,14860950,-16319031,7956142,7258061,311861,-30594991,-7379421 },
+  { -3773428,-1565936,28985340,7499440,24445838,9325937,29727763,16527196,18278453,15405622 },
+  { -4381906,8508652,-19898366,-3674424,-5984453,15149970,-13313598,843523,-21875062,13626197 },
+ },
+ {
+  { 2281448,-13487055,-10915418,-2609910,1879358,16164207,-10783882,3953792,13340839,15928663 },
+  { 31727126,-7179855,-18437503,-8283652,2875793,-16390330,-25269894,-7014826,-23452306,5964753 },
+  { 4100420,-5959452,-17179337,6017714,-18705837,12227141,-26684835,11344144,2538215,-7570755 },
+ },
+ {
+  { -9433605,6123113,11159803,-2156608,30016280,14966241,-20474983,1485421,-629256,-15958862 },
+  { -26804558,4260919,11851389,9658551,-32017107,16367492,-20205425,-13191288,11659922,-11115118 },
+  { 26180396,10015009,-30844224,-8581293,5418197,9480663,2231568,-10170080,33100372,-1306171 },
+ },
+ {
+  { 15121113,-5201871,-10389905,15427821,-27509937,-15992507,21670947,4486675,-5931810,-14466380 },
+  { 16166486,-9483733,-11104130,6023908,-31926798,-1364923,2340060,-16254968,-10735770,-10039824 },
+  { 28042865,-3557089,-12126526,12259706,-3717498,-6945899,6766453,-8689599,18036436,5803270 },
+ },
+},
+{
+ {
+  { -817581,6763912,11803561,1585585,10958447,-2671165,23855391,4598332,-6159431,-14117438 },
+  { -31031306,-14256194,17332029,-2383520,31312682,-5967183,696309,50292,-20095739,11763584 },
+  { -594563,-2514283,-32234153,12643980,12650761,14811489,665117,-12613632,-19773211,-10713562 },
+ },
+ {
+  { 30464590,-11262872,-4127476,-12734478,19835327,-7105613,-24396175,2075773,-17020157,992471 },
+  { 18357185,-6994433,7766382,16342475,-29324918,411174,14578841,8080033,-11574335,-10601610 },
+  { 19598397,10334610,12555054,2555664,18821899,-10339780,21873263,16014234,26224780,16452269 },
+ },
+ {
+  { -30223925,5145196,5944548,16385966,3976735,2009897,-11377804,-7618186,-20533829,3698650 },
+  { 14187449,3448569,-10636236,-10810935,-22663880,-3433596,7268410,-10890444,27394301,12015369 },
+  { 19695761,16087646,28032085,12999827,6817792,11427614,20244189,-1312777,-13259127,-3402461 },
+ },
+ {
+  { 30860103,12735208,-1888245,-4699734,-16974906,2256940,-8166013,12298312,-8550524,-10393462 },
+  { -5719826,-11245325,-1910649,15569035,26642876,-7587760,-5789354,-15118654,-4976164,12651793 },
+  { -2848395,9953421,11531313,-5282879,26895123,-12697089,-13118820,-16517902,9768698,-2533218 },
+ },
+ {
+  { -24719459,1894651,-287698,-4704085,15348719,-8156530,32767513,12765450,4940095,10678226 },
+  { 18860224,15980149,-18987240,-1562570,-26233012,-11071856,-7843882,13944024,-24372348,16582019 },
+  { -15504260,4970268,-29893044,4175593,-20993212,-2199756,-11704054,15444560,-11003761,7989037 },
+ },
+ {
+  { 31490452,5568061,-2412803,2182383,-32336847,4531686,-32078269,6200206,-19686113,-14800171 },
+  { -17308668,-15879940,-31522777,-2831,-32887382,16375549,8680158,-16371713,28550068,-6857132 },
+  { -28126887,-5688091,16837845,-1820458,-6850681,12700016,-30039981,4364038,1155602,5988841 },
+ },
+ {
+  { 21890435,-13272907,-12624011,12154349,-7831873,15300496,23148983,-4470481,24618407,8283181 },
+  { -33136107,-10512751,9975416,6841041,-31559793,16356536,3070187,-7025928,1466169,10740210 },
+  { -1509399,-15488185,-13503385,-10655916,32799044,909394,-13938903,-5779719,-32164649,-15327040 },
+ },
+ {
+  { 3960823,-14267803,-28026090,-15918051,-19404858,13146868,15567327,951507,-3260321,-573935 },
+  { 24740841,5052253,-30094131,8961361,25877428,6165135,-24368180,14397372,-7380369,-6144105 },
+  { -28888365,3510803,-28103278,-1158478,-11238128,-10631454,-15441463,-14453128,-1625486,-6494814 },
+ },
+},
+{
+ {
+  { 793299,-9230478,8836302,-6235707,-27360908,-2369593,33152843,-4885251,-9906200,-621852 },
+  { 5666233,525582,20782575,-8038419,-24538499,14657740,16099374,1468826,-6171428,-15186581 },
+  { -4859255,-3779343,-2917758,-6748019,7778750,11688288,-30404353,-9871238,-1558923,-9863646 },
+ },
+ {
+  { 10896332,-7719704,824275,472601,-19460308,3009587,25248958,14783338,-30581476,-15757844 },
+  { 10566929,12612572,-31944212,11118703,-12633376,12362879,21752402,8822496,24003793,14264025 },
+  { 27713862,-7355973,-11008240,9227530,27050101,2504721,23886875,-13117525,13958495,-5732453 },
+ },
+ {
+  { -23481610,4867226,-27247128,3900521,29838369,-8212291,-31889399,-10041781,7340521,-15410068 },
+  { 4646514,-8011124,-22766023,-11532654,23184553,8566613,31366726,-1381061,-15066784,-10375192 },
+  { -17270517,12723032,-16993061,14878794,21619651,-6197576,27584817,3093888,-8843694,3849921 },
+ },
+ {
+  { -9064912,2103172,25561640,-15125738,-5239824,9582958,32477045,-9017955,5002294,-15550259 },
+  { -12057553,-11177906,21115585,-13365155,8808712,-12030708,16489530,13378448,-25845716,12741426 },
+  { -5946367,10645103,-30911586,15390284,-3286982,-7118677,24306472,15852464,28834118,-7646072 },
+ },
+ {
+  { -17335748,-9107057,-24531279,9434953,-8472084,-583362,-13090771,455841,20461858,5491305 },
+  { 13669248,-16095482,-12481974,-10203039,-14569770,-11893198,-24995986,11293807,-28588204,-9421832 },
+  { 28497928,6272777,-33022994,14470570,8906179,-1225630,18504674,-14165166,29867745,-8795943 },
+ },
+ {
+  { -16207023,13517196,-27799630,-13697798,24009064,-6373891,-6367600,-13175392,22853429,-4012011 },
+  { 24191378,16712145,-13931797,15217831,14542237,1646131,18603514,-11037887,12876623,-2112447 },
+  { 17902668,4518229,-411702,-2829247,26878217,5258055,-12860753,608397,16031844,3723494 },
+ },
+ {
+  { -28632773,12763728,-20446446,7577504,33001348,-13017745,17558842,-7872890,23896954,-4314245 },
+  { -20005381,-12011952,31520464,605201,2543521,5991821,-2945064,7229064,-9919646,-8826859 },
+  { 28816045,298879,-28165016,-15920938,19000928,-1665890,-12680833,-2949325,-18051778,-2082915 },
+ },
+ {
+  { 16000882,-344896,3493092,-11447198,-29504595,-13159789,12577740,16041268,-19715240,7847707 },
+  { 10151868,10572098,27312476,7922682,14825339,4723128,-32855931,-6519018,-10020567,3852848 },
+  { -11430470,15697596,-21121557,-4420647,5386314,15063598,16514493,-15932110,29330899,-15076224 },
+ },
+},
+{
+ {
+  { -25499735,-4378794,-15222908,-6901211,16615731,2051784,3303702,15490,-27548796,12314391 },
+  { 15683520,-6003043,18109120,-9980648,15337968,-5997823,-16717435,15921866,16103996,-3731215 },
+  { -23169824,-10781249,13588192,-1628807,-3798557,-1074929,-19273607,5402699,-29815713,-9841101 },
+ },
+ {
+  { 23190676,2384583,-32714340,3462154,-29903655,-1529132,-11266856,8911517,-25205859,2739713 },
+  { 21374101,-3554250,-33524649,9874411,15377179,11831242,-33529904,6134907,4931255,11987849 },
+  { -7732,-2978858,-16223486,7277597,105524,-322051,-31480539,13861388,-30076310,10117930 },
+ },
+ {
+  { -29501170,-10744872,-26163768,13051539,-25625564,5089643,-6325503,6704079,12890019,15728940 },
+  { -21972360,-11771379,-951059,-4418840,14704840,2695116,903376,-10428139,12885167,8311031 },
+  { -17516482,5352194,10384213,-13811658,7506451,13453191,26423267,4384730,1888765,-5435404 },
+ },
+ {
+  { -25817338,-3107312,-13494599,-3182506,30896459,-13921729,-32251644,-12707869,-19464434,-3340243 },
+  { -23607977,-2665774,-526091,4651136,5765089,4618330,6092245,14845197,17151279,-9854116 },
+  { -24830458,-12733720,-15165978,10367250,-29530908,-265356,22825805,-7087279,-16866484,16176525 },
+ },
+ {
+  { -23583256,6564961,20063689,3798228,-4740178,7359225,2006182,-10363426,-28746253,-10197509 },
+  { -10626600,-4486402,-13320562,-5125317,3432136,-6393229,23632037,-1940610,32808310,1099883 },
+  { 15030977,5768825,-27451236,-2887299,-6427378,-15361371,-15277896,-6809350,2051441,-15225865 },
+ },
+ {
+  { -3362323,-7239372,7517890,9824992,23555850,295369,5148398,-14154188,-22686354,16633660 },
+  { 4577086,-16752288,13249841,-15304328,19958763,-14537274,18559670,-10759549,8402478,-9864273 },
+  { -28406330,-1051581,-26790155,-907698,-17212414,-11030789,9453451,-14980072,17983010,9967138 },
+ },
+ {
+  { -25762494,6524722,26585488,9969270,24709298,1220360,-1677990,7806337,17507396,3651560 },
+  { -10420457,-4118111,14584639,15971087,-15768321,8861010,26556809,-5574557,-18553322,-11357135 },
+  { 2839101,14284142,4029895,3472686,14402957,12689363,-26642121,8459447,-5605463,-7621941 },
+ },
+ {
+  { -4839289,-3535444,9744961,2871048,25113978,3187018,-25110813,-849066,17258084,-7977739 },
+  { 18164541,-10595176,-17154882,-1542417,19237078,-9745295,23357533,-15217008,26908270,12150756 },
+  { -30264870,-7647865,5112249,-7036672,-1499807,-6974257,43168,-5537701,-32302074,16215819 },
+ },
+},
+{
+ {
+  { -6898905,9824394,-12304779,-4401089,-31397141,-6276835,32574489,12532905,-7503072,-8675347 },
+  { -27343522,-16515468,-27151524,-10722951,946346,16291093,254968,7168080,21676107,-1943028 },
+  { 21260961,-8424752,-16831886,-11920822,-23677961,3968121,-3651949,-6215466,-3556191,-7913075 },
+ },
+ {
+  { 16544754,13250366,-16804428,15546242,-4583003,12757258,-2462308,-8680336,-18907032,-9662799 },
+  { -2415239,-15577728,18312303,4964443,-15272530,-12653564,26820651,16690659,25459437,-4564609 },
+  { -25144690,11425020,28423002,-11020557,-6144921,-15826224,9142795,-2391602,-6432418,-1644817 },
+ },
+ {
+  { -23104652,6253476,16964147,-3768872,-25113972,-12296437,-27457225,-16344658,6335692,7249989 },
+  { -30333227,13979675,7503222,-12368314,-11956721,-4621693,-30272269,2682242,25993170,-12478523 },
+  { 4364628,5930691,32304656,-10044554,-8054781,15091131,22857016,-10598955,31820368,15075278 },
+ },
+ {
+  { 31879134,-8918693,17258761,90626,-8041836,-4917709,24162788,-9650886,-17970238,12833045 },
+  { 19073683,14851414,-24403169,-11860168,7625278,11091125,-19619190,2074449,-9413939,14905377 },
+  { 24483667,-11935567,-2518866,-11547418,-1553130,15355506,-25282080,9253129,27628530,-7555480 },
+ },
+ {
+  { 17597607,8340603,19355617,552187,26198470,-3176583,4593324,-9157582,-14110875,15297016 },
+  { 510886,14337390,-31785257,16638632,6328095,2713355,-20217417,-11864220,8683221,2921426 },
+  { 18606791,11874196,27155355,-5281482,-24031742,6265446,-25178240,-1278924,4674690,13890525 },
+ },
+ {
+  { 13609624,13069022,-27372361,-13055908,24360586,9592974,14977157,9835105,4389687,288396 },
+  { 9922506,-519394,13613107,5883594,-18758345,-434263,-12304062,8317628,23388070,16052080 },
+  { 12720016,11937594,-31970060,-5028689,26900120,8561328,-20155687,-11632979,-14754271,-10812892 },
+ },
+ {
+  { 15961858,14150409,26716931,-665832,-22794328,13603569,11829573,7467844,-28822128,929275 },
+  { 11038231,-11582396,-27310482,-7316562,-10498527,-16307831,-23479533,-9371869,-21393143,2465074 },
+  { 20017163,-4323226,27915242,1529148,12396362,15675764,13817261,-9658066,2463391,-4622140 },
+ },
+ {
+  { -16358878,-12663911,-12065183,4996454,-1256422,1073572,9583558,12851107,4003896,12673717 },
+  { -1731589,-15155870,-3262930,16143082,19294135,13385325,14741514,-9103726,7903886,2348101 },
+  { 24536016,-16515207,12715592,-3862155,1511293,10047386,-3842346,-7129159,-28377538,10048127 },
+ },
+},
+{
+ {
+  { -12622226,-6204820,30718825,2591312,-10617028,12192840,18873298,-7297090,-32297756,15221632 },
+  { -26478122,-11103864,11546244,-1852483,9180880,7656409,-21343950,2095755,29769758,6593415 },
+  { -31994208,-2907461,4176912,3264766,12538965,-868111,26312345,-6118678,30958054,8292160 },
+ },
+ {
+  { 31429822,-13959116,29173532,15632448,12174511,-2760094,32808831,3977186,26143136,-3148876 },
+  { 22648901,1402143,-22799984,13746059,7936347,365344,-8668633,-1674433,-3758243,-2304625 },
+  { -15491917,8012313,-2514730,-12702462,-23965846,-10254029,-1612713,-1535569,-16664475,8194478 },
+ },
+ {
+  { 27338066,-7507420,-7414224,10140405,-19026427,-6589889,27277191,8855376,28572286,3005164 },
+  { 26287124,4821776,25476601,-4145903,-3764513,-15788984,-18008582,1182479,-26094821,-13079595 },
+  { -7171154,3178080,23970071,6201893,-17195577,-4489192,-21876275,-13982627,32208683,-1198248 },
+ },
+ {
+  { -16657702,2817643,-10286362,14811298,6024667,13349505,-27315504,-10497842,-27672585,-11539858 },
+  { 15941029,-9405932,-21367050,8062055,31876073,-238629,-15278393,-1444429,15397331,-4130193 },
+  { 8934485,-13485467,-23286397,-13423241,-32446090,14047986,31170398,-1441021,-27505566,15087184 },
+ },
+ {
+  { -18357243,-2156491,24524913,-16677868,15520427,-6360776,-15502406,11461896,16788528,-5868942 },
+  { -1947386,16013773,21750665,3714552,-17401782,-16055433,-3770287,-10323320,31322514,-11615635 },
+  { 21426655,-5650218,-13648287,-5347537,-28812189,-4920970,-18275391,-14621414,13040862,-12112948 },
+ },
+ {
+  { 11293895,12478086,-27136401,15083750,-29307421,14748872,14555558,-13417103,1613711,4896935 },
+  { -25894883,15323294,-8489791,-8057900,25967126,-13425460,2825960,-4897045,-23971776,-11267415 },
+  { -15924766,-5229880,-17443532,6410664,3622847,10243618,20615400,12405433,-23753030,-8436416 },
+ },
+ {
+  { -7091295,12556208,-20191352,9025187,-17072479,4333801,4378436,2432030,23097949,-566018 },
+  { 4565804,-16025654,20084412,-7842817,1724999,189254,24767264,10103221,-18512313,2424778 },
+  { 366633,-11976806,8173090,-6890119,30788634,5745705,-7168678,1344109,-3642553,12412659 },
+ },
+ {
+  { -24001791,7690286,14929416,-168257,-32210835,-13412986,24162697,-15326504,-3141501,11179385 },
+  { 18289522,-14724954,8056945,16430056,-21729724,7842514,-6001441,-1486897,-18684645,-11443503 },
+  { 476239,6601091,-6152790,-9723375,17503545,-4863900,27672959,13403813,11052904,5219329 },
+ },
+},
+{
+ {
+  { 20678546,-8375738,-32671898,8849123,-5009758,14574752,31186971,-3973730,9014762,-8579056 },
+  { -13644050,-10350239,-15962508,5075808,-1514661,-11534600,-33102500,9160280,8473550,-3256838 },
+  { 24900749,14435722,17209120,-15292541,-22592275,9878983,-7689309,-16335821,-24568481,11788948 },
+ },
+ {
+  { -3118155,-11395194,-13802089,14797441,9652448,-6845904,-20037437,10410733,-24568470,-1458691 },
+  { -15659161,16736706,-22467150,10215878,-9097177,7563911,11871841,-12505194,-18513325,8464118 },
+  { -23400612,8348507,-14585951,-861714,-3950205,-6373419,14325289,8628612,33313881,-8370517 },
+ },
+ {
+  { -20186973,-4967935,22367356,5271547,-1097117,-4788838,-24805667,-10236854,-8940735,-5818269 },
+  { -6948785,-1795212,-32625683,-16021179,32635414,-7374245,15989197,-12838188,28358192,-4253904 },
+  { -23561781,-2799059,-32351682,-1661963,-9147719,10429267,-16637684,4072016,-5351664,5596589 },
+ },
+ {
+  { -28236598,-3390048,12312896,6213178,3117142,16078565,29266239,2557221,1768301,15373193 },
+  { -7243358,-3246960,-4593467,-7553353,-127927,-912245,-1090902,-4504991,-24660491,3442910 },
+  { -30210571,5124043,14181784,8197961,18964734,-11939093,22597931,7176455,-18585478,13365930 },
+ },
+ {
+  { -7877390,-1499958,8324673,4690079,6261860,890446,24538107,-8570186,-9689599,-3031667 },
+  { 25008904,-10771599,-4305031,-9638010,16265036,15721635,683793,-11823784,15723479,-15163481 },
+  { -9660625,12374379,-27006999,-7026148,-7724114,-12314514,11879682,5400171,519526,-1235876 },
+ },
+ {
+  { 22258397,-16332233,-7869817,14613016,-22520255,-2950923,-20353881,7315967,16648397,7605640 },
+  { -8081308,-8464597,-8223311,9719710,19259459,-15348212,23994942,-5281555,-9468848,4763278 },
+  { -21699244,9220969,-15730624,1084137,-25476107,-2852390,31088447,-7764523,-11356529,728112 },
+ },
+ {
+  { 26047220,-11751471,-6900323,-16521798,24092068,9158119,-4273545,-12555558,-29365436,-5498272 },
+  { 17510331,-322857,5854289,8403524,17133918,-3112612,-28111007,12327945,10750447,10014012 },
+  { -10312768,3936952,9156313,-8897683,16498692,-994647,-27481051,-666732,3424691,7540221 },
+ },
+ {
+  { 30322361,-6964110,11361005,-4143317,7433304,4989748,-7071422,-16317219,-9244265,15258046 },
+  { 13054562,-2779497,19155474,469045,-12482797,4566042,5631406,2711395,1062915,-5136345 },
+  { -19240248,-11254599,-29509029,-7499965,-5835763,13005411,-6066489,12194497,32960380,1459310 },
+ },
+},
+{
+ {
+  { 19852034,7027924,23669353,10020366,8586503,-6657907,394197,-6101885,18638003,-11174937 },
+  { 31395534,15098109,26581030,8030562,-16527914,-5007134,9012486,-7584354,-6643087,-5442636 },
+  { -9192165,-2347377,-1997099,4529534,25766844,607986,-13222,9677543,-32294889,-6456008 },
+ },
+ {
+  { -2444496,-149937,29348902,8186665,1873760,12489863,-30934579,-7839692,-7852844,-8138429 },
+  { -15236356,-15433509,7766470,746860,26346930,-10221762,-27333451,10754588,-9431476,5203576 },
+  { 31834314,14135496,-770007,5159118,20917671,-16768096,-7467973,-7337524,31809243,7347066 },
+ },
+ {
+  { -9606723,-11874240,20414459,13033986,13716524,-11691881,19797970,-12211255,15192876,-2087490 },
+  { -12663563,-2181719,1168162,-3804809,26747877,-14138091,10609330,12694420,33473243,-13382104 },
+  { 33184999,11180355,15832085,-11385430,-1633671,225884,15089336,-11023903,-6135662,14480053 },
+ },
+ {
+  { 31308717,-5619998,31030840,-1897099,15674547,-6582883,5496208,13685227,27595050,8737275 },
+  { -20318852,-15150239,10933843,-16178022,8335352,-7546022,-31008351,-12610604,26498114,66511 },
+  { 22644454,-8761729,-16671776,4884562,-3105614,-13559366,30540766,-4286747,-13327787,-7515095 },
+ },
+ {
+  { -28017847,9834845,18617207,-2681312,-3401956,-13307506,8205540,13585437,-17127465,15115439 },
+  { 23711543,-672915,31206561,-8362711,6164647,-9709987,-33535882,-1426096,8236921,16492939 },
+  { -23910559,-13515526,-26299483,-4503841,25005590,-7687270,19574902,10071562,6708380,-6222424 },
+ },
+ {
+  { 2101391,-4930054,19702731,2367575,-15427167,1047675,5301017,9328700,29955601,-11678310 },
+  { 3096359,9271816,-21620864,-15521844,-14847996,-7592937,-25892142,-12635595,-9917575,6216608 },
+  { -32615849,338663,-25195611,2510422,-29213566,-13820213,24822830,-6146567,-26767480,7525079 },
+ },
+ {
+  { -23066649,-13985623,16133487,-7896178,-3389565,778788,-910336,-2782495,-19386633,11994101 },
+  { 21691500,-13624626,-641331,-14367021,3285881,-3483596,-25064666,9718258,-7477437,13381418 },
+  { 18445390,-4202236,14979846,11622458,-1727110,-3582980,23111648,-6375247,28535282,15779576 },
+ },
+ {
+  { 30098053,3089662,-9234387,16662135,-21306940,11308411,-14068454,12021730,9955285,-16303356 },
+  { 9734894,-14576830,-7473633,-9138735,2060392,11313496,-18426029,9924399,20194861,13380996 },
+  { -26378102,-7965207,-22167821,15789297,-18055342,-6168792,-1984914,15707771,26342023,10146099 },
+ },
+},
+{
+ {
+  { -26016874,-219943,21339191,-41388,19745256,-2878700,-29637280,2227040,21612326,-545728 },
+  { -13077387,1184228,23562814,-5970442,-20351244,-6348714,25764461,12243797,-20856566,11649658 },
+  { -10031494,11262626,27384172,2271902,26947504,-15997771,39944,6114064,33514190,2333242 },
+ },
+ {
+  { -21433588,-12421821,8119782,7219913,-21830522,-9016134,-6679750,-12670638,24350578,-13450001 },
+  { -4116307,-11271533,-23886186,4843615,-30088339,690623,-31536088,-10406836,8317860,12352766 },
+  { 18200138,-14475911,-33087759,-2696619,-23702521,-9102511,-23552096,-2287550,20712163,6719373 },
+ },
+ {
+  { 26656208,6075253,-7858556,1886072,-28344043,4262326,11117530,-3763210,26224235,-3297458 },
+  { -17168938,-14854097,-3395676,-16369877,-19954045,14050420,21728352,9493610,18620611,-16428628 },
+  { -13323321,13325349,11432106,5964811,18609221,6062965,-5269471,-9725556,-30701573,-16479657 },
+ },
+ {
+  { -23860538,-11233159,26961357,1640861,-32413112,-16737940,12248509,-5240639,13735342,1934062 },
+  { 25089769,6742589,17081145,-13406266,21909293,-16067981,-15136294,-3765346,-21277997,5473616 },
+  { 31883677,-7961101,1083432,-11572403,22828471,13290673,-7125085,12469656,29111212,-5451014 },
+ },
+ {
+  { 24244947,-15050407,-26262976,2791540,-14997599,16666678,24367466,6388839,-10295587,452383 },
+  { -25640782,-3417841,5217916,16224624,19987036,-4082269,-24236251,-5915248,15766062,8407814 },
+  { -20406999,13990231,15495425,16395525,5377168,15166495,-8917023,-4388953,-8067909,2276718 },
+ },
+ {
+  { 30157918,12924066,-17712050,9245753,19895028,3368142,-23827587,5096219,22740376,-7303417 },
+  { 2041139,-14256350,7783687,13876377,-25946985,-13352459,24051124,13742383,-15637599,13295222 },
+  { 33338237,-8505733,12532113,7977527,9106186,-1715251,-17720195,-4612972,-4451357,-14669444 },
+ },
+ {
+  { -20045281,5454097,-14346548,6447146,28862071,1883651,-2469266,-4141880,7770569,9620597 },
+  { 23208068,7979712,33071466,8149229,1758231,-10834995,30945528,-1694323,-33502340,-14767970 },
+  { 1439958,-16270480,-1079989,-793782,4625402,10647766,-5043801,1220118,30494170,-11440799 },
+ },
+ {
+  { -5037580,-13028295,-2970559,-3061767,15640974,-6701666,-26739026,926050,-1684339,-13333647 },
+  { 13908495,-3549272,30919928,-6273825,-21521863,7989039,9021034,9078865,3353509,4033511 },
+  { -29663431,-15113610,32259991,-344482,24295849,-12912123,23161163,8839127,27485041,7356032 },
+ },
+},
+{
+ {
+  { 9661027,705443,11980065,-5370154,-1628543,14661173,-6346142,2625015,28431036,-16771834 },
+  { -23839233,-8311415,-25945511,7480958,-17681669,-8354183,-22545972,14150565,15970762,4099461 },
+  { 29262576,16756590,26350592,-8793563,8529671,-11208050,13617293,-9937143,11465739,8317062 },
+ },
+ {
+  { -25493081,-6962928,32500200,-9419051,-23038724,-2302222,14898637,3848455,20969334,-5157516 },
+  { -20384450,-14347713,-18336405,13884722,-33039454,2842114,-21610826,-3649888,11177095,14989547 },
+  { -24496721,-11716016,16959896,2278463,12066309,10137771,13515641,2581286,-28487508,9930240 },
+ },
+ {
+  { -17751622,-2097826,16544300,-13009300,-15914807,-14949081,18345767,-13403753,16291481,-5314038 },
+  { -33229194,2553288,32678213,9875984,8534129,6889387,-9676774,6957617,4368891,9788741 },
+  { 16660756,7281060,-10830758,12911820,20108584,-8101676,-21722536,-8613148,16250552,-11111103 },
+ },
+ {
+  { -19765507,2390526,-16551031,14161980,1905286,6414907,4689584,10604807,-30190403,4782747 },
+  { -1354539,14736941,-7367442,-13292886,7710542,-14155590,-9981571,4383045,22546403,437323 },
+  { 31665577,-12180464,-16186830,1491339,-18368625,3294682,27343084,2786261,-30633590,-14097016 },
+ },
+ {
+  { -14467279,-683715,-33374107,7448552,19294360,14334329,-19690631,2355319,-19284671,-6114373 },
+  { 15121312,-15796162,6377020,-6031361,-10798111,-12957845,18952177,15496498,-29380133,11754228 },
+  { -2637277,-13483075,8488727,-14303896,12728761,-1622493,7141596,11724556,22761615,-10134141 },
+ },
+ {
+  { 16918416,11729663,-18083579,3022987,-31015732,-13339659,-28741185,-12227393,32851222,11717399 },
+  { 11166634,7338049,-6722523,4531520,-29468672,-7302055,31474879,3483633,-1193175,-4030831 },
+  { -185635,9921305,31456609,-13536438,-12013818,13348923,33142652,6546660,-19985279,-3948376 },
+ },
+ {
+  { -32460596,11266712,-11197107,-7899103,31703694,3855903,-8537131,-12833048,-30772034,-15486313 },
+  { -18006477,12709068,3991746,-6479188,-21491523,-10550425,-31135347,-16049879,10928917,3011958 },
+  { -6957757,-15594337,31696059,334240,29576716,14796075,-30831056,-12805180,18008031,10258577 },
+ },
+ {
+  { -22448644,15655569,7018479,-4410003,-30314266,-1201591,-1853465,1367120,25127874,6671743 },
+  { 29701166,-14373934,-10878120,9279288,-17568,13127210,21382910,11042292,25838796,4642684 },
+  { -20430234,14955537,-24126347,8124619,-5369288,-5990470,30468147,-13900640,18423289,4177476 },
+ },
+},
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/base.py b/crypt/monero_crypto/crypto_ops_builder/ref10/base.py
new file mode 100644
index 0000000000..84accc8580
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/base.py
@@ -0,0 +1,65 @@
+b = 256
+q = 2**255 - 19
+l = 2**252 + 27742317777372353535851937790883648493
+
+def expmod(b,e,m):
+  if e == 0: return 1
+  t = expmod(b,e/2,m)**2 % m
+  if e & 1: t = (t*b) % m
+  return t
+
+def inv(x):
+  return expmod(x,q-2,q)
+
+d = -121665 * inv(121666)
+I = expmod(2,(q-1)/4,q)
+
+def xrecover(y):
+  xx = (y*y-1) * inv(d*y*y+1)
+  x = expmod(xx,(q+3)/8,q)
+  if (x*x - xx) % q != 0: x = (x*I) % q
+  if x % 2 != 0: x = q-x
+  return x
+
+By = 4 * inv(5)
+Bx = xrecover(By)
+B = [Bx % q,By % q]
+
+def edwards(P,Q):
+  x1 = P[0]
+  y1 = P[1]
+  x2 = Q[0]
+  y2 = Q[1]
+  x3 = (x1*y2+x2*y1) * inv(1+d*x1*x2*y1*y2)
+  y3 = (y1*y2+x1*x2) * inv(1-d*x1*x2*y1*y2)
+  return [x3 % q,y3 % q]
+
+def radix255(x):
+  x = x % q
+  if x + x > q: x -= q
+  x = [x,0,0,0,0,0,0,0,0,0]
+  bits = [26,25,26,25,26,25,26,25,26,25]
+  for i in range(9):
+    carry = (x[i] + 2**(bits[i]-1)) / 2**bits[i]
+    x[i] -= carry * 2**bits[i]
+    x[i + 1] += carry
+  result = ""
+  for i in range(9):
+    result = result+str(x[i])+","
+  result = result+str(x[9])
+  return result
+
+Bi = B
+for i in range(32):
+  print "{"
+  Bij = Bi
+  for j in range(8):
+    print " {"
+    print "  {",radix255(Bij[1]+Bij[0]),"},"
+    print "  {",radix255(Bij[1]-Bij[0]),"},"
+    print "  {",radix255(2*d*Bij[0]*Bij[1]),"},"
+    Bij = edwards(Bij,Bi)
+    print " },"
+  print "},"
+  for k in range(8):
+    Bi = edwards(Bi,Bi)
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/base2.h b/crypt/monero_crypto/crypto_ops_builder/ref10/base2.h
new file mode 100644
index 0000000000..8c538440ff
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/base2.h
@@ -0,0 +1,40 @@
+ {
+  { 25967493,-14356035,29566456,3660896,-12694345,4014787,27544626,-11754271,-6079156,2047605 },
+  { -12545711,934262,-2722910,3049990,-727428,9406986,12720692,5043384,19500929,-15469378 },
+  { -8738181,4489570,9688441,-14785194,10184609,-12363380,29287919,11864899,-24514362,-4438546 },
+ },
+ {
+  { 15636291,-9688557,24204773,-7912398,616977,-16685262,27787600,-14772189,28944400,-1550024 },
+  { 16568933,4717097,-11556148,-1102322,15682896,-11807043,16354577,-11775962,7689662,11199574 },
+  { 30464156,-5976125,-11779434,-15670865,23220365,15915852,7512774,10017326,-17749093,-9920357 },
+ },
+ {
+  { 10861363,11473154,27284546,1981175,-30064349,12577861,32867885,14515107,-15438304,10819380 },
+  { 4708026,6336745,20377586,9066809,-11272109,6594696,-25653668,12483688,-12668491,5581306 },
+  { 19563160,16186464,-29386857,4097519,10237984,-4348115,28542350,13850243,-23678021,-15815942 },
+ },
+ {
+  { 5153746,9909285,1723747,-2777874,30523605,5516873,19480852,5230134,-23952439,-15175766 },
+  { -30269007,-3463509,7665486,10083793,28475525,1649722,20654025,16520125,30598449,7715701 },
+  { 28881845,14381568,9657904,3680757,-20181635,7843316,-31400660,1370708,29794553,-1409300 },
+ },
+ {
+  { -22518993,-6692182,14201702,-8745502,-23510406,8844726,18474211,-1361450,-13062696,13821877 },
+  { -6455177,-7839871,3374702,-4740862,-27098617,-10571707,31655028,-7212327,18853322,-14220951 },
+  { 4566830,-12963868,-28974889,-12240689,-7602672,-2830569,-8514358,-10431137,2207753,-3209784 },
+ },
+ {
+  { -25154831,-4185821,29681144,7868801,-6854661,-9423865,-12437364,-663000,-31111463,-16132436 },
+  { 25576264,-2703214,7349804,-11814844,16472782,9300885,3844789,15725684,171356,6466918 },
+  { 23103977,13316479,9739013,-16149481,817875,-15038942,8965339,-14088058,-30714912,16193877 },
+ },
+ {
+  { -33521811,3180713,-2394130,14003687,-16903474,-16270840,17238398,4729455,-18074513,9256800 },
+  { -25182317,-4174131,32336398,5036987,-21236817,11360617,22616405,9761698,-19827198,630305 },
+  { -13720693,2639453,-24237460,-7406481,9494427,-5774029,-6554551,-15960994,-2449256,-14291300 },
+ },
+ {
+  { -3151181,-5046075,9282714,6866145,-31907062,-863023,-18940575,15033784,25105118,-7894876 },
+  { -24326370,15950226,-31801215,-14592823,-11662737,-5090925,1573892,-2625887,2198790,-15804619 },
+  { -3099351,10324967,-2241613,7453183,-5446979,-2735503,-13812022,-16236442,-32461234,-12290683 },
+ },
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/base2.py b/crypt/monero_crypto/crypto_ops_builder/ref10/base2.py
new file mode 100644
index 0000000000..5e4e8739d0
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/base2.py
@@ -0,0 +1,60 @@
+b = 256
+q = 2**255 - 19
+l = 2**252 + 27742317777372353535851937790883648493
+
+def expmod(b,e,m):
+  if e == 0: return 1
+  t = expmod(b,e/2,m)**2 % m
+  if e & 1: t = (t*b) % m
+  return t
+
+def inv(x):
+  return expmod(x,q-2,q)
+
+d = -121665 * inv(121666)
+I = expmod(2,(q-1)/4,q)
+
+def xrecover(y):
+  xx = (y*y-1) * inv(d*y*y+1)
+  x = expmod(xx,(q+3)/8,q)
+  if (x*x - xx) % q != 0: x = (x*I) % q
+  if x % 2 != 0: x = q-x
+  return x
+
+By = 4 * inv(5)
+Bx = xrecover(By)
+B = [Bx % q,By % q]
+
+def edwards(P,Q):
+  x1 = P[0]
+  y1 = P[1]
+  x2 = Q[0]
+  y2 = Q[1]
+  x3 = (x1*y2+x2*y1) * inv(1+d*x1*x2*y1*y2)
+  y3 = (y1*y2+x1*x2) * inv(1-d*x1*x2*y1*y2)
+  return [x3 % q,y3 % q]
+
+def radix255(x):
+  x = x % q
+  if x + x > q: x -= q
+  x = [x,0,0,0,0,0,0,0,0,0]
+  bits = [26,25,26,25,26,25,26,25,26,25]
+  for i in range(9):
+    carry = (x[i] + 2**(bits[i]-1)) / 2**bits[i]
+    x[i] -= carry * 2**bits[i]
+    x[i + 1] += carry
+  result = ""
+  for i in range(9):
+    result = result+str(x[i])+","
+  result = result+str(x[9])
+  return result
+
+Bi = B
+
+for i in range(8):
+  print " {"
+  print "  {",radix255(Bi[1]+Bi[0]),"},"
+  print "  {",radix255(Bi[1]-Bi[0]),"},"
+  print "  {",radix255(2*d*Bi[0]*Bi[1]),"},"
+  print " },"
+  Bi = edwards(B,edwards(B,Bi))
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/d.h b/crypt/monero_crypto/crypto_ops_builder/ref10/d.h
new file mode 100644
index 0000000000..e25f578350
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/d.h
@@ -0,0 +1 @@
+-10913610,13857413,-15372611,6949391,114729,-8787816,-6275908,-3247719,-18696448,-12055116
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/d.py b/crypt/monero_crypto/crypto_ops_builder/ref10/d.py
new file mode 100644
index 0000000000..8995bb86a3
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/d.py
@@ -0,0 +1,28 @@
+q = 2**255 - 19
+
+def expmod(b,e,m):
+  if e == 0: return 1
+  t = expmod(b,e/2,m)**2 % m
+  if e & 1: t = (t*b) % m
+  return t
+
+def inv(x):
+  return expmod(x,q-2,q)
+
+def radix255(x):
+  x = x % q
+  if x + x > q: x -= q
+  x = [x,0,0,0,0,0,0,0,0,0]
+  bits = [26,25,26,25,26,25,26,25,26,25]
+  for i in range(9):
+    carry = (x[i] + 2**(bits[i]-1)) / 2**bits[i]
+    x[i] -= carry * 2**bits[i]
+    x[i + 1] += carry
+  result = ""
+  for i in range(9):
+    result = result+str(x[i])+","
+  result = result+str(x[9])
+  return result
+
+d = -121665 * inv(121666)
+print radix255(d)
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/d2.h b/crypt/monero_crypto/crypto_ops_builder/ref10/d2.h
new file mode 100644
index 0000000000..01aaec7512
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/d2.h
@@ -0,0 +1 @@
+-21827239,-5839606,-30745221,13898782,229458,15978800,-12551817,-6495438,29715968,9444199
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/d2.py b/crypt/monero_crypto/crypto_ops_builder/ref10/d2.py
new file mode 100644
index 0000000000..79841758be
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/d2.py
@@ -0,0 +1,28 @@
+q = 2**255 - 19
+
+def expmod(b,e,m):
+  if e == 0: return 1
+  t = expmod(b,e/2,m)**2 % m
+  if e & 1: t = (t*b) % m
+  return t
+
+def inv(x):
+  return expmod(x,q-2,q)
+
+def radix255(x):
+  x = x % q
+  if x + x > q: x -= q
+  x = [x,0,0,0,0,0,0,0,0,0]
+  bits = [26,25,26,25,26,25,26,25,26,25]
+  for i in range(9):
+    carry = (x[i] + 2**(bits[i]-1)) / 2**bits[i]
+    x[i] -= carry * 2**bits[i]
+    x[i + 1] += carry
+  result = ""
+  for i in range(9):
+    result = result+str(x[i])+","
+  result = result+str(x[9])
+  return result
+
+d = -121665 * inv(121666)
+print radix255(d*2)
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/description b/crypt/monero_crypto/crypto_ops_builder/ref10/description
new file mode 100644
index 0000000000..cbfcb2cbaf
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/description
@@ -0,0 +1,2 @@
+EdDSA signatures using Curve25519
+from http://hyperelliptic.org/ebats/supercop-20141124.tar.bz2
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/designers b/crypt/monero_crypto/crypto_ops_builder/ref10/designers
new file mode 100644
index 0000000000..2a3a93a8ee
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/designers
@@ -0,0 +1,5 @@
+Daniel J. Bernstein
+Niels Duif
+Tanja Lange
+Peter Schwabe
+Bo-Yin Yang
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/fe.h b/crypt/monero_crypto/crypto_ops_builder/ref10/fe.h
new file mode 100644
index 0000000000..60c308ba46
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/fe.h
@@ -0,0 +1,56 @@
+#ifndef FE_H
+#define FE_H
+
+#include "crypto_int32.h"
+
+typedef crypto_int32 fe[10];
+
+/*
+fe means field element.
+Here the field is \Z/(2^255-19).
+An element t, entries t[0]...t[9], represents the integer
+t[0]+2^26 t[1]+2^51 t[2]+2^77 t[3]+2^102 t[4]+...+2^230 t[9].
+Bounds on each t[i] vary depending on context.
+*/
+
+#define fe_frombytes crypto_sign_ed25519_ref10_fe_frombytes
+#define fe_tobytes crypto_sign_ed25519_ref10_fe_tobytes
+#define fe_copy crypto_sign_ed25519_ref10_fe_copy
+#define fe_isnonzero crypto_sign_ed25519_ref10_fe_isnonzero
+#define fe_isnegative crypto_sign_ed25519_ref10_fe_isnegative
+#define fe_0 crypto_sign_ed25519_ref10_fe_0
+#define fe_1 crypto_sign_ed25519_ref10_fe_1
+#define fe_cswap crypto_sign_ed25519_ref10_fe_cswap
+#define fe_cmov crypto_sign_ed25519_ref10_fe_cmov
+#define fe_add crypto_sign_ed25519_ref10_fe_add
+#define fe_sub crypto_sign_ed25519_ref10_fe_sub
+#define fe_neg crypto_sign_ed25519_ref10_fe_neg
+#define fe_mul crypto_sign_ed25519_ref10_fe_mul
+#define fe_sq crypto_sign_ed25519_ref10_fe_sq
+#define fe_sq2 crypto_sign_ed25519_ref10_fe_sq2
+#define fe_mul121666 crypto_sign_ed25519_ref10_fe_mul121666
+#define fe_invert crypto_sign_ed25519_ref10_fe_invert
+#define fe_pow22523 crypto_sign_ed25519_ref10_fe_pow22523
+
+extern void fe_frombytes(fe,const unsigned char *);
+extern void fe_tobytes(unsigned char *,const fe);
+
+extern void fe_copy(fe,const fe);
+extern int fe_isnonzero(const fe);
+extern int fe_isnegative(const fe);
+extern void fe_0(fe);
+extern void fe_1(fe);
+extern void fe_cswap(fe,fe,unsigned int);
+extern void fe_cmov(fe,const fe,unsigned int);
+
+extern void fe_add(fe,const fe,const fe);
+extern void fe_sub(fe,const fe,const fe);
+extern void fe_neg(fe,const fe);
+extern void fe_mul(fe,const fe,const fe);
+extern void fe_sq(fe,const fe);
+extern void fe_sq2(fe,const fe);
+extern void fe_mul121666(fe,const fe);
+extern void fe_invert(fe,const fe);
+extern void fe_pow22523(fe,const fe);
+
+#endif
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/fe_0.c b/crypt/monero_crypto/crypto_ops_builder/ref10/fe_0.c
new file mode 100644
index 0000000000..ec879d7337
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/fe_0.c
@@ -0,0 +1,19 @@
+#include "fe.h"
+
+/*
+h = 0
+*/
+
+void fe_0(fe h)
+{
+  h[0] = 0;
+  h[1] = 0;
+  h[2] = 0;
+  h[3] = 0;
+  h[4] = 0;
+  h[5] = 0;
+  h[6] = 0;
+  h[7] = 0;
+  h[8] = 0;
+  h[9] = 0;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/fe_1.c b/crypt/monero_crypto/crypto_ops_builder/ref10/fe_1.c
new file mode 100644
index 0000000000..8cf7784844
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/fe_1.c
@@ -0,0 +1,19 @@
+#include "fe.h"
+
+/*
+h = 1
+*/
+
+void fe_1(fe h)
+{
+  h[0] = 1;
+  h[1] = 0;
+  h[2] = 0;
+  h[3] = 0;
+  h[4] = 0;
+  h[5] = 0;
+  h[6] = 0;
+  h[7] = 0;
+  h[8] = 0;
+  h[9] = 0;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/fe_add.c b/crypt/monero_crypto/crypto_ops_builder/ref10/fe_add.c
new file mode 100644
index 0000000000..e6a81da202
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/fe_add.c
@@ -0,0 +1,57 @@
+#include "fe.h"
+
+/*
+h = f + g
+Can overlap h with f or g.
+
+Preconditions:
+   |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+   |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+
+Postconditions:
+   |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+void fe_add(fe h,const fe f,const fe g)
+{
+  crypto_int32 f0 = f[0];
+  crypto_int32 f1 = f[1];
+  crypto_int32 f2 = f[2];
+  crypto_int32 f3 = f[3];
+  crypto_int32 f4 = f[4];
+  crypto_int32 f5 = f[5];
+  crypto_int32 f6 = f[6];
+  crypto_int32 f7 = f[7];
+  crypto_int32 f8 = f[8];
+  crypto_int32 f9 = f[9];
+  crypto_int32 g0 = g[0];
+  crypto_int32 g1 = g[1];
+  crypto_int32 g2 = g[2];
+  crypto_int32 g3 = g[3];
+  crypto_int32 g4 = g[4];
+  crypto_int32 g5 = g[5];
+  crypto_int32 g6 = g[6];
+  crypto_int32 g7 = g[7];
+  crypto_int32 g8 = g[8];
+  crypto_int32 g9 = g[9];
+  crypto_int32 h0 = f0 + g0;
+  crypto_int32 h1 = f1 + g1;
+  crypto_int32 h2 = f2 + g2;
+  crypto_int32 h3 = f3 + g3;
+  crypto_int32 h4 = f4 + g4;
+  crypto_int32 h5 = f5 + g5;
+  crypto_int32 h6 = f6 + g6;
+  crypto_int32 h7 = f7 + g7;
+  crypto_int32 h8 = f8 + g8;
+  crypto_int32 h9 = f9 + g9;
+  h[0] = h0;
+  h[1] = h1;
+  h[2] = h2;
+  h[3] = h3;
+  h[4] = h4;
+  h[5] = h5;
+  h[6] = h6;
+  h[7] = h7;
+  h[8] = h8;
+  h[9] = h9;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/fe_cmov.c b/crypt/monero_crypto/crypto_ops_builder/ref10/fe_cmov.c
new file mode 100644
index 0000000000..8ca584fb19
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/fe_cmov.c
@@ -0,0 +1,63 @@
+#include "fe.h"
+
+/*
+Replace (f,g) with (g,g) if b == 1;
+replace (f,g) with (f,g) if b == 0.
+
+Preconditions: b in {0,1}.
+*/
+
+void fe_cmov(fe f,const fe g,unsigned int b)
+{
+  crypto_int32 f0 = f[0];
+  crypto_int32 f1 = f[1];
+  crypto_int32 f2 = f[2];
+  crypto_int32 f3 = f[3];
+  crypto_int32 f4 = f[4];
+  crypto_int32 f5 = f[5];
+  crypto_int32 f6 = f[6];
+  crypto_int32 f7 = f[7];
+  crypto_int32 f8 = f[8];
+  crypto_int32 f9 = f[9];
+  crypto_int32 g0 = g[0];
+  crypto_int32 g1 = g[1];
+  crypto_int32 g2 = g[2];
+  crypto_int32 g3 = g[3];
+  crypto_int32 g4 = g[4];
+  crypto_int32 g5 = g[5];
+  crypto_int32 g6 = g[6];
+  crypto_int32 g7 = g[7];
+  crypto_int32 g8 = g[8];
+  crypto_int32 g9 = g[9];
+  crypto_int32 x0 = f0 ^ g0;
+  crypto_int32 x1 = f1 ^ g1;
+  crypto_int32 x2 = f2 ^ g2;
+  crypto_int32 x3 = f3 ^ g3;
+  crypto_int32 x4 = f4 ^ g4;
+  crypto_int32 x5 = f5 ^ g5;
+  crypto_int32 x6 = f6 ^ g6;
+  crypto_int32 x7 = f7 ^ g7;
+  crypto_int32 x8 = f8 ^ g8;
+  crypto_int32 x9 = f9 ^ g9;
+  b = -b;
+  x0 &= b;
+  x1 &= b;
+  x2 &= b;
+  x3 &= b;
+  x4 &= b;
+  x5 &= b;
+  x6 &= b;
+  x7 &= b;
+  x8 &= b;
+  x9 &= b;
+  f[0] = f0 ^ x0;
+  f[1] = f1 ^ x1;
+  f[2] = f2 ^ x2;
+  f[3] = f3 ^ x3;
+  f[4] = f4 ^ x4;
+  f[5] = f5 ^ x5;
+  f[6] = f6 ^ x6;
+  f[7] = f7 ^ x7;
+  f[8] = f8 ^ x8;
+  f[9] = f9 ^ x9;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/fe_copy.c b/crypt/monero_crypto/crypto_ops_builder/ref10/fe_copy.c
new file mode 100644
index 0000000000..9c5bf865a2
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/fe_copy.c
@@ -0,0 +1,29 @@
+#include "fe.h"
+
+/*
+h = f
+*/
+
+void fe_copy(fe h,const fe f)
+{
+  crypto_int32 f0 = f[0];
+  crypto_int32 f1 = f[1];
+  crypto_int32 f2 = f[2];
+  crypto_int32 f3 = f[3];
+  crypto_int32 f4 = f[4];
+  crypto_int32 f5 = f[5];
+  crypto_int32 f6 = f[6];
+  crypto_int32 f7 = f[7];
+  crypto_int32 f8 = f[8];
+  crypto_int32 f9 = f[9];
+  h[0] = f0;
+  h[1] = f1;
+  h[2] = f2;
+  h[3] = f3;
+  h[4] = f4;
+  h[5] = f5;
+  h[6] = f6;
+  h[7] = f7;
+  h[8] = f8;
+  h[9] = f9;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/fe_frombytes.c b/crypt/monero_crypto/crypto_ops_builder/ref10/fe_frombytes.c
new file mode 100644
index 0000000000..5c17917487
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/fe_frombytes.c
@@ -0,0 +1,73 @@
+#include "fe.h"
+#include "crypto_int64.h"
+#include "crypto_uint64.h"
+
+static crypto_uint64 load_3(const unsigned char *in)
+{
+  crypto_uint64 result;
+  result = (crypto_uint64) in[0];
+  result |= ((crypto_uint64) in[1]) << 8;
+  result |= ((crypto_uint64) in[2]) << 16;
+  return result;
+}
+
+static crypto_uint64 load_4(const unsigned char *in)
+{
+  crypto_uint64 result;
+  result = (crypto_uint64) in[0];
+  result |= ((crypto_uint64) in[1]) << 8;
+  result |= ((crypto_uint64) in[2]) << 16;
+  result |= ((crypto_uint64) in[3]) << 24;
+  return result;
+}
+
+/*
+Ignores top bit of h.
+*/
+
+void fe_frombytes(fe h,const unsigned char *s)
+{
+  crypto_int64 h0 = load_4(s);
+  crypto_int64 h1 = load_3(s + 4) << 6;
+  crypto_int64 h2 = load_3(s + 7) << 5;
+  crypto_int64 h3 = load_3(s + 10) << 3;
+  crypto_int64 h4 = load_3(s + 13) << 2;
+  crypto_int64 h5 = load_4(s + 16);
+  crypto_int64 h6 = load_3(s + 20) << 7;
+  crypto_int64 h7 = load_3(s + 23) << 5;
+  crypto_int64 h8 = load_3(s + 26) << 4;
+  crypto_int64 h9 = (load_3(s + 29) & 8388607) << 2;
+  crypto_int64 carry0;
+  crypto_int64 carry1;
+  crypto_int64 carry2;
+  crypto_int64 carry3;
+  crypto_int64 carry4;
+  crypto_int64 carry5;
+  crypto_int64 carry6;
+  crypto_int64 carry7;
+  crypto_int64 carry8;
+  crypto_int64 carry9;
+
+  carry9 = (h9 + (crypto_int64) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+  carry1 = (h1 + (crypto_int64) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+  carry3 = (h3 + (crypto_int64) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+  carry5 = (h5 + (crypto_int64) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+  carry7 = (h7 + (crypto_int64) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+  carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+  carry2 = (h2 + (crypto_int64) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+  carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+  carry6 = (h6 + (crypto_int64) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+  carry8 = (h8 + (crypto_int64) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+  h[0] = h0;
+  h[1] = h1;
+  h[2] = h2;
+  h[3] = h3;
+  h[4] = h4;
+  h[5] = h5;
+  h[6] = h6;
+  h[7] = h7;
+  h[8] = h8;
+  h[9] = h9;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/fe_invert.c b/crypt/monero_crypto/crypto_ops_builder/ref10/fe_invert.c
new file mode 100644
index 0000000000..bcfdb8ff87
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/fe_invert.c
@@ -0,0 +1,14 @@
+#include "fe.h"
+
+void fe_invert(fe out,const fe z)
+{
+  fe t0;
+  fe t1;
+  fe t2;
+  fe t3;
+  int i;
+
+#include "pow225521.h"
+
+  return;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/fe_isnegative.c b/crypt/monero_crypto/crypto_ops_builder/ref10/fe_isnegative.c
new file mode 100644
index 0000000000..3b2c8b8d52
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/fe_isnegative.c
@@ -0,0 +1,16 @@
+#include "fe.h"
+
+/*
+return 1 if f is in {1,3,5,...,q-2}
+return 0 if f is in {0,2,4,...,q-1}
+
+Preconditions:
+   |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+int fe_isnegative(const fe f)
+{
+  unsigned char s[32];
+  fe_tobytes(s,f);
+  return s[0] & 1;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/fe_isnonzero.c b/crypt/monero_crypto/crypto_ops_builder/ref10/fe_isnonzero.c
new file mode 100644
index 0000000000..47568001ce
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/fe_isnonzero.c
@@ -0,0 +1,19 @@
+#include "fe.h"
+#include "crypto_verify_32.h"
+
+/*
+return 1 if f == 0
+return 0 if f != 0
+
+Preconditions:
+   |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+static const unsigned char zero[32];
+
+int fe_isnonzero(const fe f)
+{
+  unsigned char s[32];
+  fe_tobytes(s,f);
+  return crypto_verify_32(s,zero);
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/fe_mul.c b/crypt/monero_crypto/crypto_ops_builder/ref10/fe_mul.c
new file mode 100644
index 0000000000..26ca8b3682
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/fe_mul.c
@@ -0,0 +1,253 @@
+#include "fe.h"
+#include "crypto_int64.h"
+
+/*
+h = f * g
+Can overlap h with f or g.
+
+Preconditions:
+   |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+   |g| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+
+Postconditions:
+   |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
+*/
+
+/*
+Notes on implementation strategy:
+
+Using schoolbook multiplication.
+Karatsuba would save a little in some cost models.
+
+Most multiplications by 2 and 19 are 32-bit precomputations;
+cheaper than 64-bit postcomputations.
+
+There is one remaining multiplication by 19 in the carry chain;
+one *19 precomputation can be merged into this,
+but the resulting data flow is considerably less clean.
+
+There are 12 carries below.
+10 of them are 2-way parallelizable and vectorizable.
+Can get away with 11 carries, but then data flow is much deeper.
+
+With tighter constraints on inputs can squeeze carries into int32.
+*/
+
+void fe_mul(fe h,const fe f,const fe g)
+{
+  crypto_int32 f0 = f[0];
+  crypto_int32 f1 = f[1];
+  crypto_int32 f2 = f[2];
+  crypto_int32 f3 = f[3];
+  crypto_int32 f4 = f[4];
+  crypto_int32 f5 = f[5];
+  crypto_int32 f6 = f[6];
+  crypto_int32 f7 = f[7];
+  crypto_int32 f8 = f[8];
+  crypto_int32 f9 = f[9];
+  crypto_int32 g0 = g[0];
+  crypto_int32 g1 = g[1];
+  crypto_int32 g2 = g[2];
+  crypto_int32 g3 = g[3];
+  crypto_int32 g4 = g[4];
+  crypto_int32 g5 = g[5];
+  crypto_int32 g6 = g[6];
+  crypto_int32 g7 = g[7];
+  crypto_int32 g8 = g[8];
+  crypto_int32 g9 = g[9];
+  crypto_int32 g1_19 = 19 * g1; /* 1.959375*2^29 */
+  crypto_int32 g2_19 = 19 * g2; /* 1.959375*2^30; still ok */
+  crypto_int32 g3_19 = 19 * g3;
+  crypto_int32 g4_19 = 19 * g4;
+  crypto_int32 g5_19 = 19 * g5;
+  crypto_int32 g6_19 = 19 * g6;
+  crypto_int32 g7_19 = 19 * g7;
+  crypto_int32 g8_19 = 19 * g8;
+  crypto_int32 g9_19 = 19 * g9;
+  crypto_int32 f1_2 = 2 * f1;
+  crypto_int32 f3_2 = 2 * f3;
+  crypto_int32 f5_2 = 2 * f5;
+  crypto_int32 f7_2 = 2 * f7;
+  crypto_int32 f9_2 = 2 * f9;
+  crypto_int64 f0g0    = f0   * (crypto_int64) g0;
+  crypto_int64 f0g1    = f0   * (crypto_int64) g1;
+  crypto_int64 f0g2    = f0   * (crypto_int64) g2;
+  crypto_int64 f0g3    = f0   * (crypto_int64) g3;
+  crypto_int64 f0g4    = f0   * (crypto_int64) g4;
+  crypto_int64 f0g5    = f0   * (crypto_int64) g5;
+  crypto_int64 f0g6    = f0   * (crypto_int64) g6;
+  crypto_int64 f0g7    = f0   * (crypto_int64) g7;
+  crypto_int64 f0g8    = f0   * (crypto_int64) g8;
+  crypto_int64 f0g9    = f0   * (crypto_int64) g9;
+  crypto_int64 f1g0    = f1   * (crypto_int64) g0;
+  crypto_int64 f1g1_2  = f1_2 * (crypto_int64) g1;
+  crypto_int64 f1g2    = f1   * (crypto_int64) g2;
+  crypto_int64 f1g3_2  = f1_2 * (crypto_int64) g3;
+  crypto_int64 f1g4    = f1   * (crypto_int64) g4;
+  crypto_int64 f1g5_2  = f1_2 * (crypto_int64) g5;
+  crypto_int64 f1g6    = f1   * (crypto_int64) g6;
+  crypto_int64 f1g7_2  = f1_2 * (crypto_int64) g7;
+  crypto_int64 f1g8    = f1   * (crypto_int64) g8;
+  crypto_int64 f1g9_38 = f1_2 * (crypto_int64) g9_19;
+  crypto_int64 f2g0    = f2   * (crypto_int64) g0;
+  crypto_int64 f2g1    = f2   * (crypto_int64) g1;
+  crypto_int64 f2g2    = f2   * (crypto_int64) g2;
+  crypto_int64 f2g3    = f2   * (crypto_int64) g3;
+  crypto_int64 f2g4    = f2   * (crypto_int64) g4;
+  crypto_int64 f2g5    = f2   * (crypto_int64) g5;
+  crypto_int64 f2g6    = f2   * (crypto_int64) g6;
+  crypto_int64 f2g7    = f2   * (crypto_int64) g7;
+  crypto_int64 f2g8_19 = f2   * (crypto_int64) g8_19;
+  crypto_int64 f2g9_19 = f2   * (crypto_int64) g9_19;
+  crypto_int64 f3g0    = f3   * (crypto_int64) g0;
+  crypto_int64 f3g1_2  = f3_2 * (crypto_int64) g1;
+  crypto_int64 f3g2    = f3   * (crypto_int64) g2;
+  crypto_int64 f3g3_2  = f3_2 * (crypto_int64) g3;
+  crypto_int64 f3g4    = f3   * (crypto_int64) g4;
+  crypto_int64 f3g5_2  = f3_2 * (crypto_int64) g5;
+  crypto_int64 f3g6    = f3   * (crypto_int64) g6;
+  crypto_int64 f3g7_38 = f3_2 * (crypto_int64) g7_19;
+  crypto_int64 f3g8_19 = f3   * (crypto_int64) g8_19;
+  crypto_int64 f3g9_38 = f3_2 * (crypto_int64) g9_19;
+  crypto_int64 f4g0    = f4   * (crypto_int64) g0;
+  crypto_int64 f4g1    = f4   * (crypto_int64) g1;
+  crypto_int64 f4g2    = f4   * (crypto_int64) g2;
+  crypto_int64 f4g3    = f4   * (crypto_int64) g3;
+  crypto_int64 f4g4    = f4   * (crypto_int64) g4;
+  crypto_int64 f4g5    = f4   * (crypto_int64) g5;
+  crypto_int64 f4g6_19 = f4   * (crypto_int64) g6_19;
+  crypto_int64 f4g7_19 = f4   * (crypto_int64) g7_19;
+  crypto_int64 f4g8_19 = f4   * (crypto_int64) g8_19;
+  crypto_int64 f4g9_19 = f4   * (crypto_int64) g9_19;
+  crypto_int64 f5g0    = f5   * (crypto_int64) g0;
+  crypto_int64 f5g1_2  = f5_2 * (crypto_int64) g1;
+  crypto_int64 f5g2    = f5   * (crypto_int64) g2;
+  crypto_int64 f5g3_2  = f5_2 * (crypto_int64) g3;
+  crypto_int64 f5g4    = f5   * (crypto_int64) g4;
+  crypto_int64 f5g5_38 = f5_2 * (crypto_int64) g5_19;
+  crypto_int64 f5g6_19 = f5   * (crypto_int64) g6_19;
+  crypto_int64 f5g7_38 = f5_2 * (crypto_int64) g7_19;
+  crypto_int64 f5g8_19 = f5   * (crypto_int64) g8_19;
+  crypto_int64 f5g9_38 = f5_2 * (crypto_int64) g9_19;
+  crypto_int64 f6g0    = f6   * (crypto_int64) g0;
+  crypto_int64 f6g1    = f6   * (crypto_int64) g1;
+  crypto_int64 f6g2    = f6   * (crypto_int64) g2;
+  crypto_int64 f6g3    = f6   * (crypto_int64) g3;
+  crypto_int64 f6g4_19 = f6   * (crypto_int64) g4_19;
+  crypto_int64 f6g5_19 = f6   * (crypto_int64) g5_19;
+  crypto_int64 f6g6_19 = f6   * (crypto_int64) g6_19;
+  crypto_int64 f6g7_19 = f6   * (crypto_int64) g7_19;
+  crypto_int64 f6g8_19 = f6   * (crypto_int64) g8_19;
+  crypto_int64 f6g9_19 = f6   * (crypto_int64) g9_19;
+  crypto_int64 f7g0    = f7   * (crypto_int64) g0;
+  crypto_int64 f7g1_2  = f7_2 * (crypto_int64) g1;
+  crypto_int64 f7g2    = f7   * (crypto_int64) g2;
+  crypto_int64 f7g3_38 = f7_2 * (crypto_int64) g3_19;
+  crypto_int64 f7g4_19 = f7   * (crypto_int64) g4_19;
+  crypto_int64 f7g5_38 = f7_2 * (crypto_int64) g5_19;
+  crypto_int64 f7g6_19 = f7   * (crypto_int64) g6_19;
+  crypto_int64 f7g7_38 = f7_2 * (crypto_int64) g7_19;
+  crypto_int64 f7g8_19 = f7   * (crypto_int64) g8_19;
+  crypto_int64 f7g9_38 = f7_2 * (crypto_int64) g9_19;
+  crypto_int64 f8g0    = f8   * (crypto_int64) g0;
+  crypto_int64 f8g1    = f8   * (crypto_int64) g1;
+  crypto_int64 f8g2_19 = f8   * (crypto_int64) g2_19;
+  crypto_int64 f8g3_19 = f8   * (crypto_int64) g3_19;
+  crypto_int64 f8g4_19 = f8   * (crypto_int64) g4_19;
+  crypto_int64 f8g5_19 = f8   * (crypto_int64) g5_19;
+  crypto_int64 f8g6_19 = f8   * (crypto_int64) g6_19;
+  crypto_int64 f8g7_19 = f8   * (crypto_int64) g7_19;
+  crypto_int64 f8g8_19 = f8   * (crypto_int64) g8_19;
+  crypto_int64 f8g9_19 = f8   * (crypto_int64) g9_19;
+  crypto_int64 f9g0    = f9   * (crypto_int64) g0;
+  crypto_int64 f9g1_38 = f9_2 * (crypto_int64) g1_19;
+  crypto_int64 f9g2_19 = f9   * (crypto_int64) g2_19;
+  crypto_int64 f9g3_38 = f9_2 * (crypto_int64) g3_19;
+  crypto_int64 f9g4_19 = f9   * (crypto_int64) g4_19;
+  crypto_int64 f9g5_38 = f9_2 * (crypto_int64) g5_19;
+  crypto_int64 f9g6_19 = f9   * (crypto_int64) g6_19;
+  crypto_int64 f9g7_38 = f9_2 * (crypto_int64) g7_19;
+  crypto_int64 f9g8_19 = f9   * (crypto_int64) g8_19;
+  crypto_int64 f9g9_38 = f9_2 * (crypto_int64) g9_19;
+  crypto_int64 h0 = f0g0+f1g9_38+f2g8_19+f3g7_38+f4g6_19+f5g5_38+f6g4_19+f7g3_38+f8g2_19+f9g1_38;
+  crypto_int64 h1 = f0g1+f1g0   +f2g9_19+f3g8_19+f4g7_19+f5g6_19+f6g5_19+f7g4_19+f8g3_19+f9g2_19;
+  crypto_int64 h2 = f0g2+f1g1_2 +f2g0   +f3g9_38+f4g8_19+f5g7_38+f6g6_19+f7g5_38+f8g4_19+f9g3_38;
+  crypto_int64 h3 = f0g3+f1g2   +f2g1   +f3g0   +f4g9_19+f5g8_19+f6g7_19+f7g6_19+f8g5_19+f9g4_19;
+  crypto_int64 h4 = f0g4+f1g3_2 +f2g2   +f3g1_2 +f4g0   +f5g9_38+f6g8_19+f7g7_38+f8g6_19+f9g5_38;
+  crypto_int64 h5 = f0g5+f1g4   +f2g3   +f3g2   +f4g1   +f5g0   +f6g9_19+f7g8_19+f8g7_19+f9g6_19;
+  crypto_int64 h6 = f0g6+f1g5_2 +f2g4   +f3g3_2 +f4g2   +f5g1_2 +f6g0   +f7g9_38+f8g8_19+f9g7_38;
+  crypto_int64 h7 = f0g7+f1g6   +f2g5   +f3g4   +f4g3   +f5g2   +f6g1   +f7g0   +f8g9_19+f9g8_19;
+  crypto_int64 h8 = f0g8+f1g7_2 +f2g6   +f3g5_2 +f4g4   +f5g3_2 +f6g2   +f7g1_2 +f8g0   +f9g9_38;
+  crypto_int64 h9 = f0g9+f1g8   +f2g7   +f3g6   +f4g5   +f5g4   +f6g3   +f7g2   +f8g1   +f9g0   ;
+  crypto_int64 carry0;
+  crypto_int64 carry1;
+  crypto_int64 carry2;
+  crypto_int64 carry3;
+  crypto_int64 carry4;
+  crypto_int64 carry5;
+  crypto_int64 carry6;
+  crypto_int64 carry7;
+  crypto_int64 carry8;
+  crypto_int64 carry9;
+
+  /*
+  |h0| <= (1.65*1.65*2^52*(1+19+19+19+19)+1.65*1.65*2^50*(38+38+38+38+38))
+    i.e. |h0| <= 1.4*2^60; narrower ranges for h2, h4, h6, h8
+  |h1| <= (1.65*1.65*2^51*(1+1+19+19+19+19+19+19+19+19))
+    i.e. |h1| <= 1.7*2^59; narrower ranges for h3, h5, h7, h9
+  */
+
+  carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+  carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+  /* |h0| <= 2^25 */
+  /* |h4| <= 2^25 */
+  /* |h1| <= 1.71*2^59 */
+  /* |h5| <= 1.71*2^59 */
+
+  carry1 = (h1 + (crypto_int64) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+  carry5 = (h5 + (crypto_int64) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+  /* |h1| <= 2^24; from now on fits into int32 */
+  /* |h5| <= 2^24; from now on fits into int32 */
+  /* |h2| <= 1.41*2^60 */
+  /* |h6| <= 1.41*2^60 */
+
+  carry2 = (h2 + (crypto_int64) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+  carry6 = (h6 + (crypto_int64) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+  /* |h2| <= 2^25; from now on fits into int32 unchanged */
+  /* |h6| <= 2^25; from now on fits into int32 unchanged */
+  /* |h3| <= 1.71*2^59 */
+  /* |h7| <= 1.71*2^59 */
+
+  carry3 = (h3 + (crypto_int64) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+  carry7 = (h7 + (crypto_int64) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+  /* |h3| <= 2^24; from now on fits into int32 unchanged */
+  /* |h7| <= 2^24; from now on fits into int32 unchanged */
+  /* |h4| <= 1.72*2^34 */
+  /* |h8| <= 1.41*2^60 */
+
+  carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+  carry8 = (h8 + (crypto_int64) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+  /* |h4| <= 2^25; from now on fits into int32 unchanged */
+  /* |h8| <= 2^25; from now on fits into int32 unchanged */
+  /* |h5| <= 1.01*2^24 */
+  /* |h9| <= 1.71*2^59 */
+
+  carry9 = (h9 + (crypto_int64) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+  /* |h9| <= 2^24; from now on fits into int32 unchanged */
+  /* |h0| <= 1.1*2^39 */
+
+  carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+  /* |h0| <= 2^25; from now on fits into int32 unchanged */
+  /* |h1| <= 1.01*2^24 */
+
+  h[0] = h0;
+  h[1] = h1;
+  h[2] = h2;
+  h[3] = h3;
+  h[4] = h4;
+  h[5] = h5;
+  h[6] = h6;
+  h[7] = h7;
+  h[8] = h8;
+  h[9] = h9;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/fe_neg.c b/crypt/monero_crypto/crypto_ops_builder/ref10/fe_neg.c
new file mode 100644
index 0000000000..2078ce5284
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/fe_neg.c
@@ -0,0 +1,45 @@
+#include "fe.h"
+
+/*
+h = -f
+
+Preconditions:
+   |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+
+Postconditions:
+   |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+*/
+
+void fe_neg(fe h,const fe f)
+{
+  crypto_int32 f0 = f[0];
+  crypto_int32 f1 = f[1];
+  crypto_int32 f2 = f[2];
+  crypto_int32 f3 = f[3];
+  crypto_int32 f4 = f[4];
+  crypto_int32 f5 = f[5];
+  crypto_int32 f6 = f[6];
+  crypto_int32 f7 = f[7];
+  crypto_int32 f8 = f[8];
+  crypto_int32 f9 = f[9];
+  crypto_int32 h0 = -f0;
+  crypto_int32 h1 = -f1;
+  crypto_int32 h2 = -f2;
+  crypto_int32 h3 = -f3;
+  crypto_int32 h4 = -f4;
+  crypto_int32 h5 = -f5;
+  crypto_int32 h6 = -f6;
+  crypto_int32 h7 = -f7;
+  crypto_int32 h8 = -f8;
+  crypto_int32 h9 = -f9;
+  h[0] = h0;
+  h[1] = h1;
+  h[2] = h2;
+  h[3] = h3;
+  h[4] = h4;
+  h[5] = h5;
+  h[6] = h6;
+  h[7] = h7;
+  h[8] = h8;
+  h[9] = h9;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/fe_pow22523.c b/crypt/monero_crypto/crypto_ops_builder/ref10/fe_pow22523.c
new file mode 100644
index 0000000000..56675a5902
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/fe_pow22523.c
@@ -0,0 +1,13 @@
+#include "fe.h"
+
+void fe_pow22523(fe out,const fe z)
+{
+  fe t0;
+  fe t1;
+  fe t2;
+  int i;
+
+#include "pow22523.h"
+
+  return;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/fe_sq.c b/crypt/monero_crypto/crypto_ops_builder/ref10/fe_sq.c
new file mode 100644
index 0000000000..8dd119841c
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/fe_sq.c
@@ -0,0 +1,149 @@
+#include "fe.h"
+#include "crypto_int64.h"
+
+/*
+h = f * f
+Can overlap h with f.
+
+Preconditions:
+   |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+
+Postconditions:
+   |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
+*/
+
+/*
+See fe_mul.c for discussion of implementation strategy.
+*/
+
+void fe_sq(fe h,const fe f)
+{
+  crypto_int32 f0 = f[0];
+  crypto_int32 f1 = f[1];
+  crypto_int32 f2 = f[2];
+  crypto_int32 f3 = f[3];
+  crypto_int32 f4 = f[4];
+  crypto_int32 f5 = f[5];
+  crypto_int32 f6 = f[6];
+  crypto_int32 f7 = f[7];
+  crypto_int32 f8 = f[8];
+  crypto_int32 f9 = f[9];
+  crypto_int32 f0_2 = 2 * f0;
+  crypto_int32 f1_2 = 2 * f1;
+  crypto_int32 f2_2 = 2 * f2;
+  crypto_int32 f3_2 = 2 * f3;
+  crypto_int32 f4_2 = 2 * f4;
+  crypto_int32 f5_2 = 2 * f5;
+  crypto_int32 f6_2 = 2 * f6;
+  crypto_int32 f7_2 = 2 * f7;
+  crypto_int32 f5_38 = 38 * f5; /* 1.959375*2^30 */
+  crypto_int32 f6_19 = 19 * f6; /* 1.959375*2^30 */
+  crypto_int32 f7_38 = 38 * f7; /* 1.959375*2^30 */
+  crypto_int32 f8_19 = 19 * f8; /* 1.959375*2^30 */
+  crypto_int32 f9_38 = 38 * f9; /* 1.959375*2^30 */
+  crypto_int64 f0f0    = f0   * (crypto_int64) f0;
+  crypto_int64 f0f1_2  = f0_2 * (crypto_int64) f1;
+  crypto_int64 f0f2_2  = f0_2 * (crypto_int64) f2;
+  crypto_int64 f0f3_2  = f0_2 * (crypto_int64) f3;
+  crypto_int64 f0f4_2  = f0_2 * (crypto_int64) f4;
+  crypto_int64 f0f5_2  = f0_2 * (crypto_int64) f5;
+  crypto_int64 f0f6_2  = f0_2 * (crypto_int64) f6;
+  crypto_int64 f0f7_2  = f0_2 * (crypto_int64) f7;
+  crypto_int64 f0f8_2  = f0_2 * (crypto_int64) f8;
+  crypto_int64 f0f9_2  = f0_2 * (crypto_int64) f9;
+  crypto_int64 f1f1_2  = f1_2 * (crypto_int64) f1;
+  crypto_int64 f1f2_2  = f1_2 * (crypto_int64) f2;
+  crypto_int64 f1f3_4  = f1_2 * (crypto_int64) f3_2;
+  crypto_int64 f1f4_2  = f1_2 * (crypto_int64) f4;
+  crypto_int64 f1f5_4  = f1_2 * (crypto_int64) f5_2;
+  crypto_int64 f1f6_2  = f1_2 * (crypto_int64) f6;
+  crypto_int64 f1f7_4  = f1_2 * (crypto_int64) f7_2;
+  crypto_int64 f1f8_2  = f1_2 * (crypto_int64) f8;
+  crypto_int64 f1f9_76 = f1_2 * (crypto_int64) f9_38;
+  crypto_int64 f2f2    = f2   * (crypto_int64) f2;
+  crypto_int64 f2f3_2  = f2_2 * (crypto_int64) f3;
+  crypto_int64 f2f4_2  = f2_2 * (crypto_int64) f4;
+  crypto_int64 f2f5_2  = f2_2 * (crypto_int64) f5;
+  crypto_int64 f2f6_2  = f2_2 * (crypto_int64) f6;
+  crypto_int64 f2f7_2  = f2_2 * (crypto_int64) f7;
+  crypto_int64 f2f8_38 = f2_2 * (crypto_int64) f8_19;
+  crypto_int64 f2f9_38 = f2   * (crypto_int64) f9_38;
+  crypto_int64 f3f3_2  = f3_2 * (crypto_int64) f3;
+  crypto_int64 f3f4_2  = f3_2 * (crypto_int64) f4;
+  crypto_int64 f3f5_4  = f3_2 * (crypto_int64) f5_2;
+  crypto_int64 f3f6_2  = f3_2 * (crypto_int64) f6;
+  crypto_int64 f3f7_76 = f3_2 * (crypto_int64) f7_38;
+  crypto_int64 f3f8_38 = f3_2 * (crypto_int64) f8_19;
+  crypto_int64 f3f9_76 = f3_2 * (crypto_int64) f9_38;
+  crypto_int64 f4f4    = f4   * (crypto_int64) f4;
+  crypto_int64 f4f5_2  = f4_2 * (crypto_int64) f5;
+  crypto_int64 f4f6_38 = f4_2 * (crypto_int64) f6_19;
+  crypto_int64 f4f7_38 = f4   * (crypto_int64) f7_38;
+  crypto_int64 f4f8_38 = f4_2 * (crypto_int64) f8_19;
+  crypto_int64 f4f9_38 = f4   * (crypto_int64) f9_38;
+  crypto_int64 f5f5_38 = f5   * (crypto_int64) f5_38;
+  crypto_int64 f5f6_38 = f5_2 * (crypto_int64) f6_19;
+  crypto_int64 f5f7_76 = f5_2 * (crypto_int64) f7_38;
+  crypto_int64 f5f8_38 = f5_2 * (crypto_int64) f8_19;
+  crypto_int64 f5f9_76 = f5_2 * (crypto_int64) f9_38;
+  crypto_int64 f6f6_19 = f6   * (crypto_int64) f6_19;
+  crypto_int64 f6f7_38 = f6   * (crypto_int64) f7_38;
+  crypto_int64 f6f8_38 = f6_2 * (crypto_int64) f8_19;
+  crypto_int64 f6f9_38 = f6   * (crypto_int64) f9_38;
+  crypto_int64 f7f7_38 = f7   * (crypto_int64) f7_38;
+  crypto_int64 f7f8_38 = f7_2 * (crypto_int64) f8_19;
+  crypto_int64 f7f9_76 = f7_2 * (crypto_int64) f9_38;
+  crypto_int64 f8f8_19 = f8   * (crypto_int64) f8_19;
+  crypto_int64 f8f9_38 = f8   * (crypto_int64) f9_38;
+  crypto_int64 f9f9_38 = f9   * (crypto_int64) f9_38;
+  crypto_int64 h0 = f0f0  +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38;
+  crypto_int64 h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38;
+  crypto_int64 h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19;
+  crypto_int64 h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38;
+  crypto_int64 h4 = f0f4_2+f1f3_4 +f2f2   +f5f9_76+f6f8_38+f7f7_38;
+  crypto_int64 h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38;
+  crypto_int64 h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19;
+  crypto_int64 h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38;
+  crypto_int64 h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4   +f9f9_38;
+  crypto_int64 h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2;
+  crypto_int64 carry0;
+  crypto_int64 carry1;
+  crypto_int64 carry2;
+  crypto_int64 carry3;
+  crypto_int64 carry4;
+  crypto_int64 carry5;
+  crypto_int64 carry6;
+  crypto_int64 carry7;
+  crypto_int64 carry8;
+  crypto_int64 carry9;
+
+  carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+  carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+
+  carry1 = (h1 + (crypto_int64) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+  carry5 = (h5 + (crypto_int64) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+
+  carry2 = (h2 + (crypto_int64) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+  carry6 = (h6 + (crypto_int64) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+
+  carry3 = (h3 + (crypto_int64) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+  carry7 = (h7 + (crypto_int64) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+  carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+  carry8 = (h8 + (crypto_int64) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+  carry9 = (h9 + (crypto_int64) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+
+  carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+
+  h[0] = h0;
+  h[1] = h1;
+  h[2] = h2;
+  h[3] = h3;
+  h[4] = h4;
+  h[5] = h5;
+  h[6] = h6;
+  h[7] = h7;
+  h[8] = h8;
+  h[9] = h9;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/fe_sq2.c b/crypt/monero_crypto/crypto_ops_builder/ref10/fe_sq2.c
new file mode 100644
index 0000000000..026ed3aacf
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/fe_sq2.c
@@ -0,0 +1,160 @@
+#include "fe.h"
+#include "crypto_int64.h"
+
+/*
+h = 2 * f * f
+Can overlap h with f.
+
+Preconditions:
+   |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+
+Postconditions:
+   |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
+*/
+
+/*
+See fe_mul.c for discussion of implementation strategy.
+*/
+
+void fe_sq2(fe h,const fe f)
+{
+  crypto_int32 f0 = f[0];
+  crypto_int32 f1 = f[1];
+  crypto_int32 f2 = f[2];
+  crypto_int32 f3 = f[3];
+  crypto_int32 f4 = f[4];
+  crypto_int32 f5 = f[5];
+  crypto_int32 f6 = f[6];
+  crypto_int32 f7 = f[7];
+  crypto_int32 f8 = f[8];
+  crypto_int32 f9 = f[9];
+  crypto_int32 f0_2 = 2 * f0;
+  crypto_int32 f1_2 = 2 * f1;
+  crypto_int32 f2_2 = 2 * f2;
+  crypto_int32 f3_2 = 2 * f3;
+  crypto_int32 f4_2 = 2 * f4;
+  crypto_int32 f5_2 = 2 * f5;
+  crypto_int32 f6_2 = 2 * f6;
+  crypto_int32 f7_2 = 2 * f7;
+  crypto_int32 f5_38 = 38 * f5; /* 1.959375*2^30 */
+  crypto_int32 f6_19 = 19 * f6; /* 1.959375*2^30 */
+  crypto_int32 f7_38 = 38 * f7; /* 1.959375*2^30 */
+  crypto_int32 f8_19 = 19 * f8; /* 1.959375*2^30 */
+  crypto_int32 f9_38 = 38 * f9; /* 1.959375*2^30 */
+  crypto_int64 f0f0    = f0   * (crypto_int64) f0;
+  crypto_int64 f0f1_2  = f0_2 * (crypto_int64) f1;
+  crypto_int64 f0f2_2  = f0_2 * (crypto_int64) f2;
+  crypto_int64 f0f3_2  = f0_2 * (crypto_int64) f3;
+  crypto_int64 f0f4_2  = f0_2 * (crypto_int64) f4;
+  crypto_int64 f0f5_2  = f0_2 * (crypto_int64) f5;
+  crypto_int64 f0f6_2  = f0_2 * (crypto_int64) f6;
+  crypto_int64 f0f7_2  = f0_2 * (crypto_int64) f7;
+  crypto_int64 f0f8_2  = f0_2 * (crypto_int64) f8;
+  crypto_int64 f0f9_2  = f0_2 * (crypto_int64) f9;
+  crypto_int64 f1f1_2  = f1_2 * (crypto_int64) f1;
+  crypto_int64 f1f2_2  = f1_2 * (crypto_int64) f2;
+  crypto_int64 f1f3_4  = f1_2 * (crypto_int64) f3_2;
+  crypto_int64 f1f4_2  = f1_2 * (crypto_int64) f4;
+  crypto_int64 f1f5_4  = f1_2 * (crypto_int64) f5_2;
+  crypto_int64 f1f6_2  = f1_2 * (crypto_int64) f6;
+  crypto_int64 f1f7_4  = f1_2 * (crypto_int64) f7_2;
+  crypto_int64 f1f8_2  = f1_2 * (crypto_int64) f8;
+  crypto_int64 f1f9_76 = f1_2 * (crypto_int64) f9_38;
+  crypto_int64 f2f2    = f2   * (crypto_int64) f2;
+  crypto_int64 f2f3_2  = f2_2 * (crypto_int64) f3;
+  crypto_int64 f2f4_2  = f2_2 * (crypto_int64) f4;
+  crypto_int64 f2f5_2  = f2_2 * (crypto_int64) f5;
+  crypto_int64 f2f6_2  = f2_2 * (crypto_int64) f6;
+  crypto_int64 f2f7_2  = f2_2 * (crypto_int64) f7;
+  crypto_int64 f2f8_38 = f2_2 * (crypto_int64) f8_19;
+  crypto_int64 f2f9_38 = f2   * (crypto_int64) f9_38;
+  crypto_int64 f3f3_2  = f3_2 * (crypto_int64) f3;
+  crypto_int64 f3f4_2  = f3_2 * (crypto_int64) f4;
+  crypto_int64 f3f5_4  = f3_2 * (crypto_int64) f5_2;
+  crypto_int64 f3f6_2  = f3_2 * (crypto_int64) f6;
+  crypto_int64 f3f7_76 = f3_2 * (crypto_int64) f7_38;
+  crypto_int64 f3f8_38 = f3_2 * (crypto_int64) f8_19;
+  crypto_int64 f3f9_76 = f3_2 * (crypto_int64) f9_38;
+  crypto_int64 f4f4    = f4   * (crypto_int64) f4;
+  crypto_int64 f4f5_2  = f4_2 * (crypto_int64) f5;
+  crypto_int64 f4f6_38 = f4_2 * (crypto_int64) f6_19;
+  crypto_int64 f4f7_38 = f4   * (crypto_int64) f7_38;
+  crypto_int64 f4f8_38 = f4_2 * (crypto_int64) f8_19;
+  crypto_int64 f4f9_38 = f4   * (crypto_int64) f9_38;
+  crypto_int64 f5f5_38 = f5   * (crypto_int64) f5_38;
+  crypto_int64 f5f6_38 = f5_2 * (crypto_int64) f6_19;
+  crypto_int64 f5f7_76 = f5_2 * (crypto_int64) f7_38;
+  crypto_int64 f5f8_38 = f5_2 * (crypto_int64) f8_19;
+  crypto_int64 f5f9_76 = f5_2 * (crypto_int64) f9_38;
+  crypto_int64 f6f6_19 = f6   * (crypto_int64) f6_19;
+  crypto_int64 f6f7_38 = f6   * (crypto_int64) f7_38;
+  crypto_int64 f6f8_38 = f6_2 * (crypto_int64) f8_19;
+  crypto_int64 f6f9_38 = f6   * (crypto_int64) f9_38;
+  crypto_int64 f7f7_38 = f7   * (crypto_int64) f7_38;
+  crypto_int64 f7f8_38 = f7_2 * (crypto_int64) f8_19;
+  crypto_int64 f7f9_76 = f7_2 * (crypto_int64) f9_38;
+  crypto_int64 f8f8_19 = f8   * (crypto_int64) f8_19;
+  crypto_int64 f8f9_38 = f8   * (crypto_int64) f9_38;
+  crypto_int64 f9f9_38 = f9   * (crypto_int64) f9_38;
+  crypto_int64 h0 = f0f0  +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38;
+  crypto_int64 h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38;
+  crypto_int64 h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19;
+  crypto_int64 h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38;
+  crypto_int64 h4 = f0f4_2+f1f3_4 +f2f2   +f5f9_76+f6f8_38+f7f7_38;
+  crypto_int64 h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38;
+  crypto_int64 h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19;
+  crypto_int64 h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38;
+  crypto_int64 h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4   +f9f9_38;
+  crypto_int64 h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2;
+  crypto_int64 carry0;
+  crypto_int64 carry1;
+  crypto_int64 carry2;
+  crypto_int64 carry3;
+  crypto_int64 carry4;
+  crypto_int64 carry5;
+  crypto_int64 carry6;
+  crypto_int64 carry7;
+  crypto_int64 carry8;
+  crypto_int64 carry9;
+
+  h0 += h0;
+  h1 += h1;
+  h2 += h2;
+  h3 += h3;
+  h4 += h4;
+  h5 += h5;
+  h6 += h6;
+  h7 += h7;
+  h8 += h8;
+  h9 += h9;
+
+  carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+  carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+
+  carry1 = (h1 + (crypto_int64) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+  carry5 = (h5 + (crypto_int64) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+
+  carry2 = (h2 + (crypto_int64) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+  carry6 = (h6 + (crypto_int64) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+
+  carry3 = (h3 + (crypto_int64) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+  carry7 = (h7 + (crypto_int64) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+  carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+  carry8 = (h8 + (crypto_int64) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+  carry9 = (h9 + (crypto_int64) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+
+  carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+
+  h[0] = h0;
+  h[1] = h1;
+  h[2] = h2;
+  h[3] = h3;
+  h[4] = h4;
+  h[5] = h5;
+  h[6] = h6;
+  h[7] = h7;
+  h[8] = h8;
+  h[9] = h9;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/fe_sub.c b/crypt/monero_crypto/crypto_ops_builder/ref10/fe_sub.c
new file mode 100644
index 0000000000..6e26b7df8f
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/fe_sub.c
@@ -0,0 +1,57 @@
+#include "fe.h"
+
+/*
+h = f - g
+Can overlap h with f or g.
+
+Preconditions:
+   |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+   |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+
+Postconditions:
+   |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+void fe_sub(fe h,const fe f,const fe g)
+{
+  crypto_int32 f0 = f[0];
+  crypto_int32 f1 = f[1];
+  crypto_int32 f2 = f[2];
+  crypto_int32 f3 = f[3];
+  crypto_int32 f4 = f[4];
+  crypto_int32 f5 = f[5];
+  crypto_int32 f6 = f[6];
+  crypto_int32 f7 = f[7];
+  crypto_int32 f8 = f[8];
+  crypto_int32 f9 = f[9];
+  crypto_int32 g0 = g[0];
+  crypto_int32 g1 = g[1];
+  crypto_int32 g2 = g[2];
+  crypto_int32 g3 = g[3];
+  crypto_int32 g4 = g[4];
+  crypto_int32 g5 = g[5];
+  crypto_int32 g6 = g[6];
+  crypto_int32 g7 = g[7];
+  crypto_int32 g8 = g[8];
+  crypto_int32 g9 = g[9];
+  crypto_int32 h0 = f0 - g0;
+  crypto_int32 h1 = f1 - g1;
+  crypto_int32 h2 = f2 - g2;
+  crypto_int32 h3 = f3 - g3;
+  crypto_int32 h4 = f4 - g4;
+  crypto_int32 h5 = f5 - g5;
+  crypto_int32 h6 = f6 - g6;
+  crypto_int32 h7 = f7 - g7;
+  crypto_int32 h8 = f8 - g8;
+  crypto_int32 h9 = f9 - g9;
+  h[0] = h0;
+  h[1] = h1;
+  h[2] = h2;
+  h[3] = h3;
+  h[4] = h4;
+  h[5] = h5;
+  h[6] = h6;
+  h[7] = h7;
+  h[8] = h8;
+  h[9] = h9;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/fe_tobytes.c b/crypt/monero_crypto/crypto_ops_builder/ref10/fe_tobytes.c
new file mode 100644
index 0000000000..0a63baf9c1
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/fe_tobytes.c
@@ -0,0 +1,119 @@
+#include "fe.h"
+
+/*
+Preconditions:
+  |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+
+Write p=2^255-19; q=floor(h/p).
+Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))).
+
+Proof:
+  Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4.
+  Also have |h-2^230 h9|<2^231 so |19 2^(-255)(h-2^230 h9)|<1/4.
+
+  Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9).
+  Then 0<y<1.
+
+  Write r=h-pq.
+  Have 0<=r<=p-1=2^255-20.
+  Thus 0<=r+19(2^-255)r<r+19(2^-255)2^255<=2^255-1.
+
+  Write x=r+19(2^-255)r+y.
+  Then 0<x<2^255 so floor(2^(-255)x) = 0 so floor(q+2^(-255)x) = q.
+
+  Have q+2^(-255)x = 2^(-255)(h + 19 2^(-25) h9 + 2^(-1))
+  so floor(2^(-255)(h + 19 2^(-25) h9 + 2^(-1))) = q.
+*/
+
+void fe_tobytes(unsigned char *s,const fe h)
+{
+  crypto_int32 h0 = h[0];
+  crypto_int32 h1 = h[1];
+  crypto_int32 h2 = h[2];
+  crypto_int32 h3 = h[3];
+  crypto_int32 h4 = h[4];
+  crypto_int32 h5 = h[5];
+  crypto_int32 h6 = h[6];
+  crypto_int32 h7 = h[7];
+  crypto_int32 h8 = h[8];
+  crypto_int32 h9 = h[9];
+  crypto_int32 q;
+  crypto_int32 carry0;
+  crypto_int32 carry1;
+  crypto_int32 carry2;
+  crypto_int32 carry3;
+  crypto_int32 carry4;
+  crypto_int32 carry5;
+  crypto_int32 carry6;
+  crypto_int32 carry7;
+  crypto_int32 carry8;
+  crypto_int32 carry9;
+
+  q = (19 * h9 + (((crypto_int32) 1) << 24)) >> 25;
+  q = (h0 + q) >> 26;
+  q = (h1 + q) >> 25;
+  q = (h2 + q) >> 26;
+  q = (h3 + q) >> 25;
+  q = (h4 + q) >> 26;
+  q = (h5 + q) >> 25;
+  q = (h6 + q) >> 26;
+  q = (h7 + q) >> 25;
+  q = (h8 + q) >> 26;
+  q = (h9 + q) >> 25;
+
+  /* Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. */
+  h0 += 19 * q;
+  /* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */
+
+  carry0 = h0 >> 26; h1 += carry0; h0 -= carry0 << 26;
+  carry1 = h1 >> 25; h2 += carry1; h1 -= carry1 << 25;
+  carry2 = h2 >> 26; h3 += carry2; h2 -= carry2 << 26;
+  carry3 = h3 >> 25; h4 += carry3; h3 -= carry3 << 25;
+  carry4 = h4 >> 26; h5 += carry4; h4 -= carry4 << 26;
+  carry5 = h5 >> 25; h6 += carry5; h5 -= carry5 << 25;
+  carry6 = h6 >> 26; h7 += carry6; h6 -= carry6 << 26;
+  carry7 = h7 >> 25; h8 += carry7; h7 -= carry7 << 25;
+  carry8 = h8 >> 26; h9 += carry8; h8 -= carry8 << 26;
+  carry9 = h9 >> 25;               h9 -= carry9 << 25;
+                  /* h10 = carry9 */
+
+  /*
+  Goal: Output h0+...+2^255 h10-2^255 q, which is between 0 and 2^255-20.
+  Have h0+...+2^230 h9 between 0 and 2^255-1;
+  evidently 2^255 h10-2^255 q = 0.
+  Goal: Output h0+...+2^230 h9.
+  */
+
+  s[0] = h0 >> 0;
+  s[1] = h0 >> 8;
+  s[2] = h0 >> 16;
+  s[3] = (h0 >> 24) | (h1 << 2);
+  s[4] = h1 >> 6;
+  s[5] = h1 >> 14;
+  s[6] = (h1 >> 22) | (h2 << 3);
+  s[7] = h2 >> 5;
+  s[8] = h2 >> 13;
+  s[9] = (h2 >> 21) | (h3 << 5);
+  s[10] = h3 >> 3;
+  s[11] = h3 >> 11;
+  s[12] = (h3 >> 19) | (h4 << 6);
+  s[13] = h4 >> 2;
+  s[14] = h4 >> 10;
+  s[15] = h4 >> 18;
+  s[16] = h5 >> 0;
+  s[17] = h5 >> 8;
+  s[18] = h5 >> 16;
+  s[19] = (h5 >> 24) | (h6 << 1);
+  s[20] = h6 >> 7;
+  s[21] = h6 >> 15;
+  s[22] = (h6 >> 23) | (h7 << 3);
+  s[23] = h7 >> 5;
+  s[24] = h7 >> 13;
+  s[25] = (h7 >> 21) | (h8 << 4);
+  s[26] = h8 >> 4;
+  s[27] = h8 >> 12;
+  s[28] = (h8 >> 20) | (h9 << 6);
+  s[29] = h9 >> 2;
+  s[30] = h9 >> 10;
+  s[31] = h9 >> 18;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/ge.h b/crypt/monero_crypto/crypto_ops_builder/ref10/ge.h
new file mode 100644
index 0000000000..55e95f95b6
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/ge.h
@@ -0,0 +1,95 @@
+#ifndef GE_H
+#define GE_H
+
+/*
+ge means group element.
+
+Here the group is the set of pairs (x,y) of field elements (see fe.h)
+satisfying -x^2 + y^2 = 1 + d x^2y^2
+where d = -121665/121666.
+
+Representations:
+  ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z
+  ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT
+  ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T
+  ge_precomp (Duif): (y+x,y-x,2dxy)
+*/
+
+#include "fe.h"
+
+typedef struct {
+  fe X;
+  fe Y;
+  fe Z;
+} ge_p2;
+
+typedef struct {
+  fe X;
+  fe Y;
+  fe Z;
+  fe T;
+} ge_p3;
+
+typedef struct {
+  fe X;
+  fe Y;
+  fe Z;
+  fe T;
+} ge_p1p1;
+
+typedef struct {
+  fe yplusx;
+  fe yminusx;
+  fe xy2d;
+} ge_precomp;
+
+typedef struct {
+  fe YplusX;
+  fe YminusX;
+  fe Z;
+  fe T2d;
+} ge_cached;
+
+#define ge_frombytes_negate_vartime crypto_sign_ed25519_ref10_ge_frombytes_negate_vartime
+#define ge_tobytes crypto_sign_ed25519_ref10_ge_tobytes
+#define ge_p3_tobytes crypto_sign_ed25519_ref10_ge_p3_tobytes
+
+#define ge_p2_0 crypto_sign_ed25519_ref10_ge_p2_0
+#define ge_p3_0 crypto_sign_ed25519_ref10_ge_p3_0
+#define ge_precomp_0 crypto_sign_ed25519_ref10_ge_precomp_0
+#define ge_p3_to_p2 crypto_sign_ed25519_ref10_ge_p3_to_p2
+#define ge_p3_to_cached crypto_sign_ed25519_ref10_ge_p3_to_cached
+#define ge_p1p1_to_p2 crypto_sign_ed25519_ref10_ge_p1p1_to_p2
+#define ge_p1p1_to_p3 crypto_sign_ed25519_ref10_ge_p1p1_to_p3
+#define ge_p2_dbl crypto_sign_ed25519_ref10_ge_p2_dbl
+#define ge_p3_dbl crypto_sign_ed25519_ref10_ge_p3_dbl
+
+#define ge_madd crypto_sign_ed25519_ref10_ge_madd
+#define ge_msub crypto_sign_ed25519_ref10_ge_msub
+#define ge_add crypto_sign_ed25519_ref10_ge_add
+#define ge_sub crypto_sign_ed25519_ref10_ge_sub
+#define ge_scalarmult_base crypto_sign_ed25519_ref10_ge_scalarmult_base
+#define ge_double_scalarmult_vartime crypto_sign_ed25519_ref10_ge_double_scalarmult_vartime
+
+extern void ge_tobytes(unsigned char *,const ge_p2 *);
+extern void ge_p3_tobytes(unsigned char *,const ge_p3 *);
+extern int ge_frombytes_negate_vartime(ge_p3 *,const unsigned char *);
+
+extern void ge_p2_0(ge_p2 *);
+extern void ge_p3_0(ge_p3 *);
+extern void ge_precomp_0(ge_precomp *);
+extern void ge_p3_to_p2(ge_p2 *,const ge_p3 *);
+extern void ge_p3_to_cached(ge_cached *,const ge_p3 *);
+extern void ge_p1p1_to_p2(ge_p2 *,const ge_p1p1 *);
+extern void ge_p1p1_to_p3(ge_p3 *,const ge_p1p1 *);
+extern void ge_p2_dbl(ge_p1p1 *,const ge_p2 *);
+extern void ge_p3_dbl(ge_p1p1 *,const ge_p3 *);
+
+extern void ge_madd(ge_p1p1 *,const ge_p3 *,const ge_precomp *);
+extern void ge_msub(ge_p1p1 *,const ge_p3 *,const ge_precomp *);
+extern void ge_add(ge_p1p1 *,const ge_p3 *,const ge_cached *);
+extern void ge_sub(ge_p1p1 *,const ge_p3 *,const ge_cached *);
+extern void ge_scalarmult_base(ge_p3 *,const unsigned char *);
+extern void ge_double_scalarmult_vartime(ge_p2 *,const unsigned char *,const ge_p3 *,const unsigned char *);
+
+#endif
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/ge_add.c b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_add.c
new file mode 100644
index 0000000000..da7ff5d2eb
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_add.c
@@ -0,0 +1,11 @@
+#include "ge.h"
+
+/*
+r = p + q
+*/
+
+void ge_add(ge_p1p1 *r,const ge_p3 *p,const ge_cached *q)
+{
+  fe t0;
+#include "ge_add.h"
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/ge_add.h b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_add.h
new file mode 100644
index 0000000000..7481f8ffbe
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_add.h
@@ -0,0 +1,97 @@
+
+/* qhasm: enter ge_add */
+
+/* qhasm: fe X1 */
+
+/* qhasm: fe Y1 */
+
+/* qhasm: fe Z1 */
+
+/* qhasm: fe Z2 */
+
+/* qhasm: fe T1 */
+
+/* qhasm: fe ZZ */
+
+/* qhasm: fe YpX2 */
+
+/* qhasm: fe YmX2 */
+
+/* qhasm: fe T2d2 */
+
+/* qhasm: fe X3 */
+
+/* qhasm: fe Y3 */
+
+/* qhasm: fe Z3 */
+
+/* qhasm: fe T3 */
+
+/* qhasm: fe YpX1 */
+
+/* qhasm: fe YmX1 */
+
+/* qhasm: fe A */
+
+/* qhasm: fe B */
+
+/* qhasm: fe C */
+
+/* qhasm: fe D */
+
+/* qhasm: YpX1 = Y1+X1 */
+/* asm 1: fe_add(>YpX1=fe#1,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_add(>YpX1=r->X,<Y1=p->Y,<X1=p->X); */
+fe_add(r->X,p->Y,p->X);
+
+/* qhasm: YmX1 = Y1-X1 */
+/* asm 1: fe_sub(>YmX1=fe#2,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_sub(>YmX1=r->Y,<Y1=p->Y,<X1=p->X); */
+fe_sub(r->Y,p->Y,p->X);
+
+/* qhasm: A = YpX1*YpX2 */
+/* asm 1: fe_mul(>A=fe#3,<YpX1=fe#1,<YpX2=fe#15); */
+/* asm 2: fe_mul(>A=r->Z,<YpX1=r->X,<YpX2=q->YplusX); */
+fe_mul(r->Z,r->X,q->YplusX);
+
+/* qhasm: B = YmX1*YmX2 */
+/* asm 1: fe_mul(>B=fe#2,<YmX1=fe#2,<YmX2=fe#16); */
+/* asm 2: fe_mul(>B=r->Y,<YmX1=r->Y,<YmX2=q->YminusX); */
+fe_mul(r->Y,r->Y,q->YminusX);
+
+/* qhasm: C = T2d2*T1 */
+/* asm 1: fe_mul(>C=fe#4,<T2d2=fe#18,<T1=fe#14); */
+/* asm 2: fe_mul(>C=r->T,<T2d2=q->T2d,<T1=p->T); */
+fe_mul(r->T,q->T2d,p->T);
+
+/* qhasm: ZZ = Z1*Z2 */
+/* asm 1: fe_mul(>ZZ=fe#1,<Z1=fe#13,<Z2=fe#17); */
+/* asm 2: fe_mul(>ZZ=r->X,<Z1=p->Z,<Z2=q->Z); */
+fe_mul(r->X,p->Z,q->Z);
+
+/* qhasm: D = 2*ZZ */
+/* asm 1: fe_add(>D=fe#5,<ZZ=fe#1,<ZZ=fe#1); */
+/* asm 2: fe_add(>D=t0,<ZZ=r->X,<ZZ=r->X); */
+fe_add(t0,r->X,r->X);
+
+/* qhasm: X3 = A-B */
+/* asm 1: fe_sub(>X3=fe#1,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_sub(>X3=r->X,<A=r->Z,<B=r->Y); */
+fe_sub(r->X,r->Z,r->Y);
+
+/* qhasm: Y3 = A+B */
+/* asm 1: fe_add(>Y3=fe#2,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_add(>Y3=r->Y,<A=r->Z,<B=r->Y); */
+fe_add(r->Y,r->Z,r->Y);
+
+/* qhasm: Z3 = D+C */
+/* asm 1: fe_add(>Z3=fe#3,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_add(>Z3=r->Z,<D=t0,<C=r->T); */
+fe_add(r->Z,t0,r->T);
+
+/* qhasm: T3 = D-C */
+/* asm 1: fe_sub(>T3=fe#4,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_sub(>T3=r->T,<D=t0,<C=r->T); */
+fe_sub(r->T,t0,r->T);
+
+/* qhasm: return */
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/ge_add.q b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_add.q
new file mode 100644
index 0000000000..a6572ab0f8
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_add.q
@@ -0,0 +1,49 @@
+:name:fe:r->X:r->Y:r->Z:r->T:t0:t1:t2:t3:t4:t5:p->X:p->Y:p->Z:p->T:q->YplusX:q->YminusX:q->Z:q->T2d:
+fe r:var/r=fe:
+
+enter f:enter/f:>X1=fe#11:>Y1=fe#12:>Z1=fe#13:>T1=fe#14:>YpX2=fe#15:>YmX2=fe#16:>Z2=fe#17:>T2d2=fe#18:
+return:nofallthrough:<X3=fe#1:<Y3=fe#2:<Z3=fe#3:<T3=fe#4:leave:
+
+h=f+g:<f=fe:<g=fe:>h=fe:asm/fe_add(>h,<f,<g);:
+h=f-g:<f=fe:<g=fe:>h=fe:asm/fe_sub(>h,<f,<g);:
+h=f*g:<f=fe:<g=fe:>h=fe:asm/fe_mul(>h,<f,<g);:
+h=f^2:<f=fe:>h=fe:asm/fe_sq(>h,<f);:
+h=2*g:<g=fe:>h=fe:asm/fe_add(>h,<g,<g);:
+
+:
+
+enter ge_add
+
+fe X1
+fe Y1
+fe Z1
+fe Z2
+fe T1
+fe ZZ
+fe YpX2
+fe YmX2
+fe T2d2
+fe X3
+fe Y3
+fe Z3
+fe T3
+fe YpX1
+fe YmX1
+fe A
+fe B
+fe C
+fe D
+
+YpX1 = Y1+X1
+YmX1 = Y1-X1
+A = YpX1*YpX2
+B = YmX1*YmX2
+C = T2d2*T1
+ZZ = Z1*Z2
+D = 2*ZZ
+X3 = A-B
+Y3 = A+B
+Z3 = D+C
+T3 = D-C
+
+return
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/ge_double_scalarmult.c b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_double_scalarmult.c
new file mode 100644
index 0000000000..f8bf4bf775
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_double_scalarmult.c
@@ -0,0 +1,96 @@
+#include "ge.h"
+
+static void slide(signed char *r,const unsigned char *a)
+{
+  int i;
+  int b;
+  int k;
+
+  for (i = 0;i < 256;++i)
+    r[i] = 1 & (a[i >> 3] >> (i & 7));
+
+  for (i = 0;i < 256;++i)
+    if (r[i]) {
+      for (b = 1;b <= 6 && i + b < 256;++b) {
+        if (r[i + b]) {
+          if (r[i] + (r[i + b] << b) <= 15) {
+            r[i] += r[i + b] << b; r[i + b] = 0;
+          } else if (r[i] - (r[i + b] << b) >= -15) {
+            r[i] -= r[i + b] << b;
+            for (k = i + b;k < 256;++k) {
+              if (!r[k]) {
+                r[k] = 1;
+                break;
+              }
+              r[k] = 0;
+            }
+          } else
+            break;
+        }
+      }
+    }
+
+}
+
+static ge_precomp Bi[8] = {
+#include "base2.h"
+} ;
+
+/*
+r = a * A + b * B
+where a = a[0]+256*a[1]+...+256^31 a[31].
+and b = b[0]+256*b[1]+...+256^31 b[31].
+B is the Ed25519 base point (x,4/5) with x positive.
+*/
+
+void ge_double_scalarmult_vartime(ge_p2 *r,const unsigned char *a,const ge_p3 *A,const unsigned char *b)
+{
+  signed char aslide[256];
+  signed char bslide[256];
+  ge_cached Ai[8]; /* A,3A,5A,7A,9A,11A,13A,15A */
+  ge_p1p1 t;
+  ge_p3 u;
+  ge_p3 A2;
+  int i;
+
+  slide(aslide,a);
+  slide(bslide,b);
+
+  ge_p3_to_cached(&Ai[0],A);
+  ge_p3_dbl(&t,A); ge_p1p1_to_p3(&A2,&t);
+  ge_add(&t,&A2,&Ai[0]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[1],&u);
+  ge_add(&t,&A2,&Ai[1]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[2],&u);
+  ge_add(&t,&A2,&Ai[2]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[3],&u);
+  ge_add(&t,&A2,&Ai[3]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[4],&u);
+  ge_add(&t,&A2,&Ai[4]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[5],&u);
+  ge_add(&t,&A2,&Ai[5]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[6],&u);
+  ge_add(&t,&A2,&Ai[6]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[7],&u);
+
+  ge_p2_0(r);
+
+  for (i = 255;i >= 0;--i) {
+    if (aslide[i] || bslide[i]) break;
+  }
+
+  for (;i >= 0;--i) {
+    ge_p2_dbl(&t,r);
+
+    if (aslide[i] > 0) {
+      ge_p1p1_to_p3(&u,&t);
+      ge_add(&t,&u,&Ai[aslide[i]/2]);
+    } else if (aslide[i] < 0) {
+      ge_p1p1_to_p3(&u,&t);
+      ge_sub(&t,&u,&Ai[(-aslide[i])/2]);
+    }
+
+    if (bslide[i] > 0) {
+      ge_p1p1_to_p3(&u,&t);
+      ge_madd(&t,&u,&Bi[bslide[i]/2]);
+    } else if (bslide[i] < 0) {
+      ge_p1p1_to_p3(&u,&t);
+      ge_msub(&t,&u,&Bi[(-bslide[i])/2]);
+    }
+
+    ge_p1p1_to_p2(r,&t);
+  }
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/ge_frombytes.c b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_frombytes.c
new file mode 100644
index 0000000000..1a059ee93f
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_frombytes.c
@@ -0,0 +1,50 @@
+#include "ge.h"
+
+static const fe d = {
+#include "d.h"
+} ;
+
+static const fe sqrtm1 = {
+#include "sqrtm1.h"
+} ;
+
+int ge_frombytes_negate_vartime(ge_p3 *h,const unsigned char *s)
+{
+  fe u;
+  fe v;
+  fe v3;
+  fe vxx;
+  fe check;
+
+  fe_frombytes(h->Y,s);
+  fe_1(h->Z);
+  fe_sq(u,h->Y);
+  fe_mul(v,u,d);
+  fe_sub(u,u,h->Z);       /* u = y^2-1 */
+  fe_add(v,v,h->Z);       /* v = dy^2+1 */
+
+  fe_sq(v3,v);
+  fe_mul(v3,v3,v);        /* v3 = v^3 */
+  fe_sq(h->X,v3);
+  fe_mul(h->X,h->X,v);
+  fe_mul(h->X,h->X,u);    /* x = uv^7 */
+
+  fe_pow22523(h->X,h->X); /* x = (uv^7)^((q-5)/8) */
+  fe_mul(h->X,h->X,v3);
+  fe_mul(h->X,h->X,u);    /* x = uv^3(uv^7)^((q-5)/8) */
+
+  fe_sq(vxx,h->X);
+  fe_mul(vxx,vxx,v);
+  fe_sub(check,vxx,u);    /* vx^2-u */
+  if (fe_isnonzero(check)) {
+    fe_add(check,vxx,u);  /* vx^2+u */
+    if (fe_isnonzero(check)) return -1;
+    fe_mul(h->X,h->X,sqrtm1);
+  }
+
+  if (fe_isnegative(h->X) == (s[31] >> 7))
+    fe_neg(h->X,h->X);
+
+  fe_mul(h->T,h->X,h->Y);
+  return 0;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/ge_madd.c b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_madd.c
new file mode 100644
index 0000000000..622571774b
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_madd.c
@@ -0,0 +1,11 @@
+#include "ge.h"
+
+/*
+r = p + q
+*/
+
+void ge_madd(ge_p1p1 *r,const ge_p3 *p,const ge_precomp *q)
+{
+  fe t0;
+#include "ge_madd.h"
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/ge_madd.h b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_madd.h
new file mode 100644
index 0000000000..ecae84952b
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_madd.h
@@ -0,0 +1,88 @@
+
+/* qhasm: enter ge_madd */
+
+/* qhasm: fe X1 */
+
+/* qhasm: fe Y1 */
+
+/* qhasm: fe Z1 */
+
+/* qhasm: fe T1 */
+
+/* qhasm: fe ypx2 */
+
+/* qhasm: fe ymx2 */
+
+/* qhasm: fe xy2d2 */
+
+/* qhasm: fe X3 */
+
+/* qhasm: fe Y3 */
+
+/* qhasm: fe Z3 */
+
+/* qhasm: fe T3 */
+
+/* qhasm: fe YpX1 */
+
+/* qhasm: fe YmX1 */
+
+/* qhasm: fe A */
+
+/* qhasm: fe B */
+
+/* qhasm: fe C */
+
+/* qhasm: fe D */
+
+/* qhasm: YpX1 = Y1+X1 */
+/* asm 1: fe_add(>YpX1=fe#1,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_add(>YpX1=r->X,<Y1=p->Y,<X1=p->X); */
+fe_add(r->X,p->Y,p->X);
+
+/* qhasm: YmX1 = Y1-X1 */
+/* asm 1: fe_sub(>YmX1=fe#2,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_sub(>YmX1=r->Y,<Y1=p->Y,<X1=p->X); */
+fe_sub(r->Y,p->Y,p->X);
+
+/* qhasm: A = YpX1*ypx2 */
+/* asm 1: fe_mul(>A=fe#3,<YpX1=fe#1,<ypx2=fe#15); */
+/* asm 2: fe_mul(>A=r->Z,<YpX1=r->X,<ypx2=q->yplusx); */
+fe_mul(r->Z,r->X,q->yplusx);
+
+/* qhasm: B = YmX1*ymx2 */
+/* asm 1: fe_mul(>B=fe#2,<YmX1=fe#2,<ymx2=fe#16); */
+/* asm 2: fe_mul(>B=r->Y,<YmX1=r->Y,<ymx2=q->yminusx); */
+fe_mul(r->Y,r->Y,q->yminusx);
+
+/* qhasm: C = xy2d2*T1 */
+/* asm 1: fe_mul(>C=fe#4,<xy2d2=fe#17,<T1=fe#14); */
+/* asm 2: fe_mul(>C=r->T,<xy2d2=q->xy2d,<T1=p->T); */
+fe_mul(r->T,q->xy2d,p->T);
+
+/* qhasm: D = 2*Z1 */
+/* asm 1: fe_add(>D=fe#5,<Z1=fe#13,<Z1=fe#13); */
+/* asm 2: fe_add(>D=t0,<Z1=p->Z,<Z1=p->Z); */
+fe_add(t0,p->Z,p->Z);
+
+/* qhasm: X3 = A-B */
+/* asm 1: fe_sub(>X3=fe#1,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_sub(>X3=r->X,<A=r->Z,<B=r->Y); */
+fe_sub(r->X,r->Z,r->Y);
+
+/* qhasm: Y3 = A+B */
+/* asm 1: fe_add(>Y3=fe#2,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_add(>Y3=r->Y,<A=r->Z,<B=r->Y); */
+fe_add(r->Y,r->Z,r->Y);
+
+/* qhasm: Z3 = D+C */
+/* asm 1: fe_add(>Z3=fe#3,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_add(>Z3=r->Z,<D=t0,<C=r->T); */
+fe_add(r->Z,t0,r->T);
+
+/* qhasm: T3 = D-C */
+/* asm 1: fe_sub(>T3=fe#4,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_sub(>T3=r->T,<D=t0,<C=r->T); */
+fe_sub(r->T,t0,r->T);
+
+/* qhasm: return */
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/ge_madd.q b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_madd.q
new file mode 100644
index 0000000000..aa3db454e6
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_madd.q
@@ -0,0 +1,46 @@
+:name:fe:r->X:r->Y:r->Z:r->T:t0:t1:t2:t3:t4:t5:p->X:p->Y:p->Z:p->T:q->yplusx:q->yminusx:q->xy2d:
+fe r:var/r=fe:
+
+enter f:enter/f:>X1=fe#11:>Y1=fe#12:>Z1=fe#13:>T1=fe#14:>ypx2=fe#15:>ymx2=fe#16:>xy2d2=fe#17:
+return:nofallthrough:<X3=fe#1:<Y3=fe#2:<Z3=fe#3:<T3=fe#4:leave:
+
+h=f+g:<f=fe:<g=fe:>h=fe:asm/fe_add(>h,<f,<g);:
+h=f-g:<f=fe:<g=fe:>h=fe:asm/fe_sub(>h,<f,<g);:
+h=f*g:<f=fe:<g=fe:>h=fe:asm/fe_mul(>h,<f,<g);:
+h=f^2:<f=fe:>h=fe:asm/fe_sq(>h,<f);:
+h=2*g:<g=fe:>h=fe:asm/fe_add(>h,<g,<g);:
+
+:
+
+enter ge_madd
+
+fe X1
+fe Y1
+fe Z1
+fe T1
+fe ypx2
+fe ymx2
+fe xy2d2
+fe X3
+fe Y3
+fe Z3
+fe T3
+fe YpX1
+fe YmX1
+fe A
+fe B
+fe C
+fe D
+
+YpX1 = Y1+X1
+YmX1 = Y1-X1
+A = YpX1*ypx2
+B = YmX1*ymx2
+C = xy2d2*T1
+D = 2*Z1
+X3 = A-B
+Y3 = A+B
+Z3 = D+C
+T3 = D-C
+
+return
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/ge_msub.c b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_msub.c
new file mode 100644
index 0000000000..741ecbf113
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_msub.c
@@ -0,0 +1,11 @@
+#include "ge.h"
+
+/*
+r = p - q
+*/
+
+void ge_msub(ge_p1p1 *r,const ge_p3 *p,const ge_precomp *q)
+{
+  fe t0;
+#include "ge_msub.h"
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/ge_msub.h b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_msub.h
new file mode 100644
index 0000000000..500f986ba0
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_msub.h
@@ -0,0 +1,88 @@
+
+/* qhasm: enter ge_msub */
+
+/* qhasm: fe X1 */
+
+/* qhasm: fe Y1 */
+
+/* qhasm: fe Z1 */
+
+/* qhasm: fe T1 */
+
+/* qhasm: fe ypx2 */
+
+/* qhasm: fe ymx2 */
+
+/* qhasm: fe xy2d2 */
+
+/* qhasm: fe X3 */
+
+/* qhasm: fe Y3 */
+
+/* qhasm: fe Z3 */
+
+/* qhasm: fe T3 */
+
+/* qhasm: fe YpX1 */
+
+/* qhasm: fe YmX1 */
+
+/* qhasm: fe A */
+
+/* qhasm: fe B */
+
+/* qhasm: fe C */
+
+/* qhasm: fe D */
+
+/* qhasm: YpX1 = Y1+X1 */
+/* asm 1: fe_add(>YpX1=fe#1,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_add(>YpX1=r->X,<Y1=p->Y,<X1=p->X); */
+fe_add(r->X,p->Y,p->X);
+
+/* qhasm: YmX1 = Y1-X1 */
+/* asm 1: fe_sub(>YmX1=fe#2,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_sub(>YmX1=r->Y,<Y1=p->Y,<X1=p->X); */
+fe_sub(r->Y,p->Y,p->X);
+
+/* qhasm: A = YpX1*ymx2 */
+/* asm 1: fe_mul(>A=fe#3,<YpX1=fe#1,<ymx2=fe#16); */
+/* asm 2: fe_mul(>A=r->Z,<YpX1=r->X,<ymx2=q->yminusx); */
+fe_mul(r->Z,r->X,q->yminusx);
+
+/* qhasm: B = YmX1*ypx2 */
+/* asm 1: fe_mul(>B=fe#2,<YmX1=fe#2,<ypx2=fe#15); */
+/* asm 2: fe_mul(>B=r->Y,<YmX1=r->Y,<ypx2=q->yplusx); */
+fe_mul(r->Y,r->Y,q->yplusx);
+
+/* qhasm: C = xy2d2*T1 */
+/* asm 1: fe_mul(>C=fe#4,<xy2d2=fe#17,<T1=fe#14); */
+/* asm 2: fe_mul(>C=r->T,<xy2d2=q->xy2d,<T1=p->T); */
+fe_mul(r->T,q->xy2d,p->T);
+
+/* qhasm: D = 2*Z1 */
+/* asm 1: fe_add(>D=fe#5,<Z1=fe#13,<Z1=fe#13); */
+/* asm 2: fe_add(>D=t0,<Z1=p->Z,<Z1=p->Z); */
+fe_add(t0,p->Z,p->Z);
+
+/* qhasm: X3 = A-B */
+/* asm 1: fe_sub(>X3=fe#1,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_sub(>X3=r->X,<A=r->Z,<B=r->Y); */
+fe_sub(r->X,r->Z,r->Y);
+
+/* qhasm: Y3 = A+B */
+/* asm 1: fe_add(>Y3=fe#2,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_add(>Y3=r->Y,<A=r->Z,<B=r->Y); */
+fe_add(r->Y,r->Z,r->Y);
+
+/* qhasm: Z3 = D-C */
+/* asm 1: fe_sub(>Z3=fe#3,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_sub(>Z3=r->Z,<D=t0,<C=r->T); */
+fe_sub(r->Z,t0,r->T);
+
+/* qhasm: T3 = D+C */
+/* asm 1: fe_add(>T3=fe#4,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_add(>T3=r->T,<D=t0,<C=r->T); */
+fe_add(r->T,t0,r->T);
+
+/* qhasm: return */
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/ge_msub.q b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_msub.q
new file mode 100644
index 0000000000..e3cadd882d
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_msub.q
@@ -0,0 +1,46 @@
+:name:fe:r->X:r->Y:r->Z:r->T:t0:t1:t2:t3:t4:t5:p->X:p->Y:p->Z:p->T:q->yplusx:q->yminusx:q->xy2d:
+fe r:var/r=fe:
+
+enter f:enter/f:>X1=fe#11:>Y1=fe#12:>Z1=fe#13:>T1=fe#14:>ypx2=fe#15:>ymx2=fe#16:>xy2d2=fe#17:
+return:nofallthrough:<X3=fe#1:<Y3=fe#2:<Z3=fe#3:<T3=fe#4:leave:
+
+h=f+g:<f=fe:<g=fe:>h=fe:asm/fe_add(>h,<f,<g);:
+h=f-g:<f=fe:<g=fe:>h=fe:asm/fe_sub(>h,<f,<g);:
+h=f*g:<f=fe:<g=fe:>h=fe:asm/fe_mul(>h,<f,<g);:
+h=f^2:<f=fe:>h=fe:asm/fe_sq(>h,<f);:
+h=2*g:<g=fe:>h=fe:asm/fe_add(>h,<g,<g);:
+
+:
+
+enter ge_msub
+
+fe X1
+fe Y1
+fe Z1
+fe T1
+fe ypx2
+fe ymx2
+fe xy2d2
+fe X3
+fe Y3
+fe Z3
+fe T3
+fe YpX1
+fe YmX1
+fe A
+fe B
+fe C
+fe D
+
+YpX1 = Y1+X1
+YmX1 = Y1-X1
+A = YpX1*ymx2
+B = YmX1*ypx2
+C = xy2d2*T1
+D = 2*Z1
+X3 = A-B
+Y3 = A+B
+Z3 = D-C
+T3 = D+C
+
+return
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/ge_p1p1_to_p2.c b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_p1p1_to_p2.c
new file mode 100644
index 0000000000..9bb5013d66
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_p1p1_to_p2.c
@@ -0,0 +1,12 @@
+#include "ge.h"
+
+/*
+r = p
+*/
+
+extern void ge_p1p1_to_p2(ge_p2 *r,const ge_p1p1 *p)
+{
+  fe_mul(r->X,p->X,p->T);
+  fe_mul(r->Y,p->Y,p->Z);
+  fe_mul(r->Z,p->Z,p->T);
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/ge_p1p1_to_p3.c b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_p1p1_to_p3.c
new file mode 100644
index 0000000000..2f57b10968
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_p1p1_to_p3.c
@@ -0,0 +1,13 @@
+#include "ge.h"
+
+/*
+r = p
+*/
+
+extern void ge_p1p1_to_p3(ge_p3 *r,const ge_p1p1 *p)
+{
+  fe_mul(r->X,p->X,p->T);
+  fe_mul(r->Y,p->Y,p->Z);
+  fe_mul(r->Z,p->Z,p->T);
+  fe_mul(r->T,p->X,p->Y);
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/ge_p2_0.c b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_p2_0.c
new file mode 100644
index 0000000000..6191d1e6e4
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_p2_0.c
@@ -0,0 +1,8 @@
+#include "ge.h"
+
+void ge_p2_0(ge_p2 *h)
+{
+  fe_0(h->X);
+  fe_1(h->Y);
+  fe_1(h->Z);
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/ge_p2_dbl.c b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_p2_dbl.c
new file mode 100644
index 0000000000..2e332b5cee
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_p2_dbl.c
@@ -0,0 +1,11 @@
+#include "ge.h"
+
+/*
+r = 2 * p
+*/
+
+void ge_p2_dbl(ge_p1p1 *r,const ge_p2 *p)
+{
+  fe t0;
+#include "ge_p2_dbl.h"
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/ge_p2_dbl.h b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_p2_dbl.h
new file mode 100644
index 0000000000..128efed907
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_p2_dbl.h
@@ -0,0 +1,73 @@
+
+/* qhasm: enter ge_p2_dbl */
+
+/* qhasm: fe X1 */
+
+/* qhasm: fe Y1 */
+
+/* qhasm: fe Z1 */
+
+/* qhasm: fe A */
+
+/* qhasm: fe AA */
+
+/* qhasm: fe XX */
+
+/* qhasm: fe YY */
+
+/* qhasm: fe B */
+
+/* qhasm: fe X3 */
+
+/* qhasm: fe Y3 */
+
+/* qhasm: fe Z3 */
+
+/* qhasm: fe T3 */
+
+/* qhasm: XX=X1^2 */
+/* asm 1: fe_sq(>XX=fe#1,<X1=fe#11); */
+/* asm 2: fe_sq(>XX=r->X,<X1=p->X); */
+fe_sq(r->X,p->X);
+
+/* qhasm: YY=Y1^2 */
+/* asm 1: fe_sq(>YY=fe#3,<Y1=fe#12); */
+/* asm 2: fe_sq(>YY=r->Z,<Y1=p->Y); */
+fe_sq(r->Z,p->Y);
+
+/* qhasm: B=2*Z1^2 */
+/* asm 1: fe_sq2(>B=fe#4,<Z1=fe#13); */
+/* asm 2: fe_sq2(>B=r->T,<Z1=p->Z); */
+fe_sq2(r->T,p->Z);
+
+/* qhasm: A=X1+Y1 */
+/* asm 1: fe_add(>A=fe#2,<X1=fe#11,<Y1=fe#12); */
+/* asm 2: fe_add(>A=r->Y,<X1=p->X,<Y1=p->Y); */
+fe_add(r->Y,p->X,p->Y);
+
+/* qhasm: AA=A^2 */
+/* asm 1: fe_sq(>AA=fe#5,<A=fe#2); */
+/* asm 2: fe_sq(>AA=t0,<A=r->Y); */
+fe_sq(t0,r->Y);
+
+/* qhasm: Y3=YY+XX */
+/* asm 1: fe_add(>Y3=fe#2,<YY=fe#3,<XX=fe#1); */
+/* asm 2: fe_add(>Y3=r->Y,<YY=r->Z,<XX=r->X); */
+fe_add(r->Y,r->Z,r->X);
+
+/* qhasm: Z3=YY-XX */
+/* asm 1: fe_sub(>Z3=fe#3,<YY=fe#3,<XX=fe#1); */
+/* asm 2: fe_sub(>Z3=r->Z,<YY=r->Z,<XX=r->X); */
+fe_sub(r->Z,r->Z,r->X);
+
+/* qhasm: X3=AA-Y3 */
+/* asm 1: fe_sub(>X3=fe#1,<AA=fe#5,<Y3=fe#2); */
+/* asm 2: fe_sub(>X3=r->X,<AA=t0,<Y3=r->Y); */
+fe_sub(r->X,t0,r->Y);
+
+/* qhasm: T3=B-Z3 */
+/* asm 1: fe_sub(>T3=fe#4,<B=fe#4,<Z3=fe#3); */
+/* asm 2: fe_sub(>T3=r->T,<B=r->T,<Z3=r->Z); */
+fe_sub(r->T,r->T,r->Z);
+
+/* qhasm: return */
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/ge_p2_dbl.q b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_p2_dbl.q
new file mode 100644
index 0000000000..170d42f9a7
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_p2_dbl.q
@@ -0,0 +1,41 @@
+:name:fe:r->X:r->Y:r->Z:r->T:t0:t1:t2:t3:t4:t5:p->X:p->Y:p->Z:
+fe r:var/r=fe:
+
+enter f:enter/f:>X1=fe#11:>Y1=fe#12:>Z1=fe#13:
+return:nofallthrough:<X3=fe#1:<Y3=fe#2:<Z3=fe#3:<T3=fe#4:leave:
+
+h=f+g:<f=fe:<g=fe:>h=fe:asm/fe_add(>h,<f,<g);:
+h=f-g:<f=fe:<g=fe:>h=fe:asm/fe_sub(>h,<f,<g);:
+h=f*g:<f=fe:<g=fe:>h=fe:asm/fe_mul(>h,<f,<g);:
+h=f^2:<f=fe:>h=fe:asm/fe_sq(>h,<f);:
+h=2*f^2:<f=fe:>h=fe:asm/fe_sq2(>h,<f);:
+h=2*g:<g=fe:>h=fe:asm/fe_add(>h,<g,<g);:
+
+:
+
+enter ge_p2_dbl
+
+fe X1
+fe Y1
+fe Z1
+fe A
+fe AA
+fe XX
+fe YY
+fe B
+fe X3
+fe Y3
+fe Z3
+fe T3
+
+XX=X1^2
+YY=Y1^2
+B=2*Z1^2
+A=X1+Y1
+AA=A^2
+Y3=YY+XX
+Z3=YY-XX
+X3=AA-Y3
+T3=B-Z3
+
+return
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/ge_p3_0.c b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_p3_0.c
new file mode 100644
index 0000000000..401b2935a1
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_p3_0.c
@@ -0,0 +1,9 @@
+#include "ge.h"
+
+void ge_p3_0(ge_p3 *h)
+{
+  fe_0(h->X);
+  fe_1(h->Y);
+  fe_1(h->Z);
+  fe_0(h->T);
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/ge_p3_dbl.c b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_p3_dbl.c
new file mode 100644
index 0000000000..0d8a05915d
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_p3_dbl.c
@@ -0,0 +1,12 @@
+#include "ge.h"
+
+/*
+r = 2 * p
+*/
+
+void ge_p3_dbl(ge_p1p1 *r,const ge_p3 *p)
+{
+  ge_p2 q;
+  ge_p3_to_p2(&q,p);
+  ge_p2_dbl(r,&q);
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/ge_p3_to_cached.c b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_p3_to_cached.c
new file mode 100644
index 0000000000..bde64228cf
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_p3_to_cached.c
@@ -0,0 +1,17 @@
+#include "ge.h"
+
+/*
+r = p
+*/
+
+static const fe d2 = {
+#include "d2.h"
+} ;
+
+extern void ge_p3_to_cached(ge_cached *r,const ge_p3 *p)
+{
+  fe_add(r->YplusX,p->Y,p->X);
+  fe_sub(r->YminusX,p->Y,p->X);
+  fe_copy(r->Z,p->Z);
+  fe_mul(r->T2d,p->T,d2);
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/ge_p3_to_p2.c b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_p3_to_p2.c
new file mode 100644
index 0000000000..e532a9e4cb
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_p3_to_p2.c
@@ -0,0 +1,12 @@
+#include "ge.h"
+
+/*
+r = p
+*/
+
+extern void ge_p3_to_p2(ge_p2 *r,const ge_p3 *p)
+{
+  fe_copy(r->X,p->X);
+  fe_copy(r->Y,p->Y);
+  fe_copy(r->Z,p->Z);
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/ge_p3_tobytes.c b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_p3_tobytes.c
new file mode 100644
index 0000000000..21cb2fc656
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_p3_tobytes.c
@@ -0,0 +1,14 @@
+#include "ge.h"
+
+void ge_p3_tobytes(unsigned char *s,const ge_p3 *h)
+{
+  fe recip;
+  fe x;
+  fe y;
+
+  fe_invert(recip,h->Z);
+  fe_mul(x,h->X,recip);
+  fe_mul(y,h->Y,recip);
+  fe_tobytes(s,y);
+  s[31] ^= fe_isnegative(x) << 7;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/ge_precomp_0.c b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_precomp_0.c
new file mode 100644
index 0000000000..2e218861d8
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_precomp_0.c
@@ -0,0 +1,8 @@
+#include "ge.h"
+
+void ge_precomp_0(ge_precomp *h)
+{
+  fe_1(h->yplusx);
+  fe_1(h->yminusx);
+  fe_0(h->xy2d);
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/ge_scalarmult_base.c b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_scalarmult_base.c
new file mode 100644
index 0000000000..421e4fa0fb
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_scalarmult_base.c
@@ -0,0 +1,105 @@
+#include "ge.h"
+#include "crypto_uint32.h"
+
+static unsigned char equal(signed char b,signed char c)
+{
+  unsigned char ub = b;
+  unsigned char uc = c;
+  unsigned char x = ub ^ uc; /* 0: yes; 1..255: no */
+  crypto_uint32 y = x; /* 0: yes; 1..255: no */
+  y -= 1; /* 4294967295: yes; 0..254: no */
+  y >>= 31; /* 1: yes; 0: no */
+  return y;
+}
+
+static unsigned char negative(signed char b)
+{
+  unsigned long long x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */
+  x >>= 63; /* 1: yes; 0: no */
+  return x;
+}
+
+static void cmov(ge_precomp *t,ge_precomp *u,unsigned char b)
+{
+  fe_cmov(t->yplusx,u->yplusx,b);
+  fe_cmov(t->yminusx,u->yminusx,b);
+  fe_cmov(t->xy2d,u->xy2d,b);
+}
+
+/* base[i][j] = (j+1)*256^i*B */
+static ge_precomp base[32][8] = {
+#include "base.h"
+} ;
+
+static void select(ge_precomp *t,int pos,signed char b)
+{
+  ge_precomp minust;
+  unsigned char bnegative = negative(b);
+  unsigned char babs = b - (((-bnegative) & b) << 1);
+
+  ge_precomp_0(t);
+  cmov(t,&base[pos][0],equal(babs,1));
+  cmov(t,&base[pos][1],equal(babs,2));
+  cmov(t,&base[pos][2],equal(babs,3));
+  cmov(t,&base[pos][3],equal(babs,4));
+  cmov(t,&base[pos][4],equal(babs,5));
+  cmov(t,&base[pos][5],equal(babs,6));
+  cmov(t,&base[pos][6],equal(babs,7));
+  cmov(t,&base[pos][7],equal(babs,8));
+  fe_copy(minust.yplusx,t->yminusx);
+  fe_copy(minust.yminusx,t->yplusx);
+  fe_neg(minust.xy2d,t->xy2d);
+  cmov(t,&minust,bnegative);
+}
+
+/*
+h = a * B
+where a = a[0]+256*a[1]+...+256^31 a[31]
+B is the Ed25519 base point (x,4/5) with x positive.
+
+Preconditions:
+  a[31] <= 127
+*/
+
+void ge_scalarmult_base(ge_p3 *h,const unsigned char *a)
+{
+  signed char e[64];
+  signed char carry;
+  ge_p1p1 r;
+  ge_p2 s;
+  ge_precomp t;
+  int i;
+
+  for (i = 0;i < 32;++i) {
+    e[2 * i + 0] = (a[i] >> 0) & 15;
+    e[2 * i + 1] = (a[i] >> 4) & 15;
+  }
+  /* each e[i] is between 0 and 15 */
+  /* e[63] is between 0 and 7 */
+
+  carry = 0;
+  for (i = 0;i < 63;++i) {
+    e[i] += carry;
+    carry = e[i] + 8;
+    carry >>= 4;
+    e[i] -= carry << 4;
+  }
+  e[63] += carry;
+  /* each e[i] is between -8 and 8 */
+
+  ge_p3_0(h);
+  for (i = 1;i < 64;i += 2) {
+    select(&t,i / 2,e[i]);
+    ge_madd(&r,h,&t); ge_p1p1_to_p3(h,&r);
+  }
+
+  ge_p3_dbl(&r,h);  ge_p1p1_to_p2(&s,&r);
+  ge_p2_dbl(&r,&s); ge_p1p1_to_p2(&s,&r);
+  ge_p2_dbl(&r,&s); ge_p1p1_to_p2(&s,&r);
+  ge_p2_dbl(&r,&s); ge_p1p1_to_p3(h,&r);
+
+  for (i = 0;i < 64;i += 2) {
+    select(&t,i / 2,e[i]);
+    ge_madd(&r,h,&t); ge_p1p1_to_p3(h,&r);
+  }
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/ge_sub.c b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_sub.c
new file mode 100644
index 0000000000..69f3d54062
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_sub.c
@@ -0,0 +1,11 @@
+#include "ge.h"
+
+/*
+r = p - q
+*/
+
+void ge_sub(ge_p1p1 *r,const ge_p3 *p,const ge_cached *q)
+{
+  fe t0;
+#include "ge_sub.h"
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/ge_sub.h b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_sub.h
new file mode 100644
index 0000000000..b4ef1f5dd0
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_sub.h
@@ -0,0 +1,97 @@
+
+/* qhasm: enter ge_sub */
+
+/* qhasm: fe X1 */
+
+/* qhasm: fe Y1 */
+
+/* qhasm: fe Z1 */
+
+/* qhasm: fe Z2 */
+
+/* qhasm: fe T1 */
+
+/* qhasm: fe ZZ */
+
+/* qhasm: fe YpX2 */
+
+/* qhasm: fe YmX2 */
+
+/* qhasm: fe T2d2 */
+
+/* qhasm: fe X3 */
+
+/* qhasm: fe Y3 */
+
+/* qhasm: fe Z3 */
+
+/* qhasm: fe T3 */
+
+/* qhasm: fe YpX1 */
+
+/* qhasm: fe YmX1 */
+
+/* qhasm: fe A */
+
+/* qhasm: fe B */
+
+/* qhasm: fe C */
+
+/* qhasm: fe D */
+
+/* qhasm: YpX1 = Y1+X1 */
+/* asm 1: fe_add(>YpX1=fe#1,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_add(>YpX1=r->X,<Y1=p->Y,<X1=p->X); */
+fe_add(r->X,p->Y,p->X);
+
+/* qhasm: YmX1 = Y1-X1 */
+/* asm 1: fe_sub(>YmX1=fe#2,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_sub(>YmX1=r->Y,<Y1=p->Y,<X1=p->X); */
+fe_sub(r->Y,p->Y,p->X);
+
+/* qhasm: A = YpX1*YmX2 */
+/* asm 1: fe_mul(>A=fe#3,<YpX1=fe#1,<YmX2=fe#16); */
+/* asm 2: fe_mul(>A=r->Z,<YpX1=r->X,<YmX2=q->YminusX); */
+fe_mul(r->Z,r->X,q->YminusX);
+
+/* qhasm: B = YmX1*YpX2 */
+/* asm 1: fe_mul(>B=fe#2,<YmX1=fe#2,<YpX2=fe#15); */
+/* asm 2: fe_mul(>B=r->Y,<YmX1=r->Y,<YpX2=q->YplusX); */
+fe_mul(r->Y,r->Y,q->YplusX);
+
+/* qhasm: C = T2d2*T1 */
+/* asm 1: fe_mul(>C=fe#4,<T2d2=fe#18,<T1=fe#14); */
+/* asm 2: fe_mul(>C=r->T,<T2d2=q->T2d,<T1=p->T); */
+fe_mul(r->T,q->T2d,p->T);
+
+/* qhasm: ZZ = Z1*Z2 */
+/* asm 1: fe_mul(>ZZ=fe#1,<Z1=fe#13,<Z2=fe#17); */
+/* asm 2: fe_mul(>ZZ=r->X,<Z1=p->Z,<Z2=q->Z); */
+fe_mul(r->X,p->Z,q->Z);
+
+/* qhasm: D = 2*ZZ */
+/* asm 1: fe_add(>D=fe#5,<ZZ=fe#1,<ZZ=fe#1); */
+/* asm 2: fe_add(>D=t0,<ZZ=r->X,<ZZ=r->X); */
+fe_add(t0,r->X,r->X);
+
+/* qhasm: X3 = A-B */
+/* asm 1: fe_sub(>X3=fe#1,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_sub(>X3=r->X,<A=r->Z,<B=r->Y); */
+fe_sub(r->X,r->Z,r->Y);
+
+/* qhasm: Y3 = A+B */
+/* asm 1: fe_add(>Y3=fe#2,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_add(>Y3=r->Y,<A=r->Z,<B=r->Y); */
+fe_add(r->Y,r->Z,r->Y);
+
+/* qhasm: Z3 = D-C */
+/* asm 1: fe_sub(>Z3=fe#3,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_sub(>Z3=r->Z,<D=t0,<C=r->T); */
+fe_sub(r->Z,t0,r->T);
+
+/* qhasm: T3 = D+C */
+/* asm 1: fe_add(>T3=fe#4,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_add(>T3=r->T,<D=t0,<C=r->T); */
+fe_add(r->T,t0,r->T);
+
+/* qhasm: return */
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/ge_sub.q b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_sub.q
new file mode 100644
index 0000000000..2779a4a201
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_sub.q
@@ -0,0 +1,49 @@
+:name:fe:r->X:r->Y:r->Z:r->T:t0:t1:t2:t3:t4:t5:p->X:p->Y:p->Z:p->T:q->YplusX:q->YminusX:q->Z:q->T2d:
+fe r:var/r=fe:
+
+enter f:enter/f:>X1=fe#11:>Y1=fe#12:>Z1=fe#13:>T1=fe#14:>YpX2=fe#15:>YmX2=fe#16:>Z2=fe#17:>T2d2=fe#18:
+return:nofallthrough:<X3=fe#1:<Y3=fe#2:<Z3=fe#3:<T3=fe#4:leave:
+
+h=f+g:<f=fe:<g=fe:>h=fe:asm/fe_add(>h,<f,<g);:
+h=f-g:<f=fe:<g=fe:>h=fe:asm/fe_sub(>h,<f,<g);:
+h=f*g:<f=fe:<g=fe:>h=fe:asm/fe_mul(>h,<f,<g);:
+h=f^2:<f=fe:>h=fe:asm/fe_sq(>h,<f);:
+h=2*g:<g=fe:>h=fe:asm/fe_add(>h,<g,<g);:
+
+:
+
+enter ge_sub
+
+fe X1
+fe Y1
+fe Z1
+fe Z2
+fe T1
+fe ZZ
+fe YpX2
+fe YmX2
+fe T2d2
+fe X3
+fe Y3
+fe Z3
+fe T3
+fe YpX1
+fe YmX1
+fe A
+fe B
+fe C
+fe D
+
+YpX1 = Y1+X1
+YmX1 = Y1-X1
+A = YpX1*YmX2
+B = YmX1*YpX2
+C = T2d2*T1
+ZZ = Z1*Z2
+D = 2*ZZ
+X3 = A-B
+Y3 = A+B
+Z3 = D-C
+T3 = D+C
+
+return
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/ge_tobytes.c b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_tobytes.c
new file mode 100644
index 0000000000..31b3d33e09
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/ge_tobytes.c
@@ -0,0 +1,14 @@
+#include "ge.h"
+
+void ge_tobytes(unsigned char *s,const ge_p2 *h)
+{
+  fe recip;
+  fe x;
+  fe y;
+
+  fe_invert(recip,h->Z);
+  fe_mul(x,h->X,recip);
+  fe_mul(y,h->Y,recip);
+  fe_tobytes(s,y);
+  s[31] ^= fe_isnegative(x) << 7;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/keypair.c b/crypt/monero_crypto/crypto_ops_builder/ref10/keypair.c
new file mode 100644
index 0000000000..ac6cea2b7a
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/keypair.c
@@ -0,0 +1,23 @@
+#include <string.h>
+#include "randombytes.h"
+#include "crypto_sign.h"
+#include "crypto_hash_sha512.h"
+#include "ge.h"
+
+int crypto_sign_keypair(unsigned char *pk,unsigned char *sk)
+{
+  unsigned char az[64];
+  ge_p3 A;
+
+  randombytes(sk,32);
+  crypto_hash_sha512(az,sk,32);
+  az[0] &= 248;
+  az[31] &= 63;
+  az[31] |= 64;
+
+  ge_scalarmult_base(&A,az);
+  ge_p3_tobytes(pk,&A);
+
+  memmove(sk + 32,pk,32);
+  return 0;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/open.c b/crypt/monero_crypto/crypto_ops_builder/ref10/open.c
new file mode 100644
index 0000000000..1ec4cd2bfd
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/open.c
@@ -0,0 +1,48 @@
+#include <string.h>
+#include "crypto_sign.h"
+#include "crypto_hash_sha512.h"
+#include "crypto_verify_32.h"
+#include "ge.h"
+#include "sc.h"
+
+int crypto_sign_open(
+  unsigned char *m,unsigned long long *mlen,
+  const unsigned char *sm,unsigned long long smlen,
+  const unsigned char *pk
+)
+{
+  unsigned char pkcopy[32];
+  unsigned char rcopy[32];
+  unsigned char scopy[32];
+  unsigned char h[64];
+  unsigned char rcheck[32];
+  ge_p3 A;
+  ge_p2 R;
+
+  if (smlen < 64) goto badsig;
+  if (sm[63] & 224) goto badsig;
+  if (ge_frombytes_negate_vartime(&A,pk) != 0) goto badsig;
+
+  memmove(pkcopy,pk,32);
+  memmove(rcopy,sm,32);
+  memmove(scopy,sm + 32,32);
+
+  memmove(m,sm,smlen);
+  memmove(m + 32,pkcopy,32);
+  crypto_hash_sha512(h,m,smlen);
+  sc_reduce(h);
+
+  ge_double_scalarmult_vartime(&R,h,&A,scopy);
+  ge_tobytes(rcheck,&R);
+  if (crypto_verify_32(rcheck,rcopy) == 0) {
+    memmove(m,m + 64,smlen - 64);
+    memset(m + smlen - 64,0,64);
+    *mlen = smlen - 64;
+    return 0;
+  }
+
+badsig:
+  *mlen = -1;
+  memset(m,0,smlen);
+  return -1;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/pow22523.h b/crypt/monero_crypto/crypto_ops_builder/ref10/pow22523.h
new file mode 100644
index 0000000000..60ffe0d34c
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/pow22523.h
@@ -0,0 +1,160 @@
+
+/* qhasm: fe z1 */
+
+/* qhasm: fe z2 */
+
+/* qhasm: fe z8 */
+
+/* qhasm: fe z9 */
+
+/* qhasm: fe z11 */
+
+/* qhasm: fe z22 */
+
+/* qhasm: fe z_5_0 */
+
+/* qhasm: fe z_10_5 */
+
+/* qhasm: fe z_10_0 */
+
+/* qhasm: fe z_20_10 */
+
+/* qhasm: fe z_20_0 */
+
+/* qhasm: fe z_40_20 */
+
+/* qhasm: fe z_40_0 */
+
+/* qhasm: fe z_50_10 */
+
+/* qhasm: fe z_50_0 */
+
+/* qhasm: fe z_100_50 */
+
+/* qhasm: fe z_100_0 */
+
+/* qhasm: fe z_200_100 */
+
+/* qhasm: fe z_200_0 */
+
+/* qhasm: fe z_250_50 */
+
+/* qhasm: fe z_250_0 */
+
+/* qhasm: fe z_252_2 */
+
+/* qhasm: fe z_252_3 */
+
+/* qhasm: enter pow22523 */
+
+/* qhasm: z2 = z1^2^1 */
+/* asm 1: fe_sq(>z2=fe#1,<z1=fe#11); for (i = 1;i < 1;++i) fe_sq(>z2=fe#1,>z2=fe#1); */
+/* asm 2: fe_sq(>z2=t0,<z1=z); for (i = 1;i < 1;++i) fe_sq(>z2=t0,>z2=t0); */
+fe_sq(t0,z); for (i = 1;i < 1;++i) fe_sq(t0,t0);
+
+/* qhasm: z8 = z2^2^2 */
+/* asm 1: fe_sq(>z8=fe#2,<z2=fe#1); for (i = 1;i < 2;++i) fe_sq(>z8=fe#2,>z8=fe#2); */
+/* asm 2: fe_sq(>z8=t1,<z2=t0); for (i = 1;i < 2;++i) fe_sq(>z8=t1,>z8=t1); */
+fe_sq(t1,t0); for (i = 1;i < 2;++i) fe_sq(t1,t1);
+
+/* qhasm: z9 = z1*z8 */
+/* asm 1: fe_mul(>z9=fe#2,<z1=fe#11,<z8=fe#2); */
+/* asm 2: fe_mul(>z9=t1,<z1=z,<z8=t1); */
+fe_mul(t1,z,t1);
+
+/* qhasm: z11 = z2*z9 */
+/* asm 1: fe_mul(>z11=fe#1,<z2=fe#1,<z9=fe#2); */
+/* asm 2: fe_mul(>z11=t0,<z2=t0,<z9=t1); */
+fe_mul(t0,t0,t1);
+
+/* qhasm: z22 = z11^2^1 */
+/* asm 1: fe_sq(>z22=fe#1,<z11=fe#1); for (i = 1;i < 1;++i) fe_sq(>z22=fe#1,>z22=fe#1); */
+/* asm 2: fe_sq(>z22=t0,<z11=t0); for (i = 1;i < 1;++i) fe_sq(>z22=t0,>z22=t0); */
+fe_sq(t0,t0); for (i = 1;i < 1;++i) fe_sq(t0,t0);
+
+/* qhasm: z_5_0 = z9*z22 */
+/* asm 1: fe_mul(>z_5_0=fe#1,<z9=fe#2,<z22=fe#1); */
+/* asm 2: fe_mul(>z_5_0=t0,<z9=t1,<z22=t0); */
+fe_mul(t0,t1,t0);
+
+/* qhasm: z_10_5 = z_5_0^2^5 */
+/* asm 1: fe_sq(>z_10_5=fe#2,<z_5_0=fe#1); for (i = 1;i < 5;++i) fe_sq(>z_10_5=fe#2,>z_10_5=fe#2); */
+/* asm 2: fe_sq(>z_10_5=t1,<z_5_0=t0); for (i = 1;i < 5;++i) fe_sq(>z_10_5=t1,>z_10_5=t1); */
+fe_sq(t1,t0); for (i = 1;i < 5;++i) fe_sq(t1,t1);
+
+/* qhasm: z_10_0 = z_10_5*z_5_0 */
+/* asm 1: fe_mul(>z_10_0=fe#1,<z_10_5=fe#2,<z_5_0=fe#1); */
+/* asm 2: fe_mul(>z_10_0=t0,<z_10_5=t1,<z_5_0=t0); */
+fe_mul(t0,t1,t0);
+
+/* qhasm: z_20_10 = z_10_0^2^10 */
+/* asm 1: fe_sq(>z_20_10=fe#2,<z_10_0=fe#1); for (i = 1;i < 10;++i) fe_sq(>z_20_10=fe#2,>z_20_10=fe#2); */
+/* asm 2: fe_sq(>z_20_10=t1,<z_10_0=t0); for (i = 1;i < 10;++i) fe_sq(>z_20_10=t1,>z_20_10=t1); */
+fe_sq(t1,t0); for (i = 1;i < 10;++i) fe_sq(t1,t1);
+
+/* qhasm: z_20_0 = z_20_10*z_10_0 */
+/* asm 1: fe_mul(>z_20_0=fe#2,<z_20_10=fe#2,<z_10_0=fe#1); */
+/* asm 2: fe_mul(>z_20_0=t1,<z_20_10=t1,<z_10_0=t0); */
+fe_mul(t1,t1,t0);
+
+/* qhasm: z_40_20 = z_20_0^2^20 */
+/* asm 1: fe_sq(>z_40_20=fe#3,<z_20_0=fe#2); for (i = 1;i < 20;++i) fe_sq(>z_40_20=fe#3,>z_40_20=fe#3); */
+/* asm 2: fe_sq(>z_40_20=t2,<z_20_0=t1); for (i = 1;i < 20;++i) fe_sq(>z_40_20=t2,>z_40_20=t2); */
+fe_sq(t2,t1); for (i = 1;i < 20;++i) fe_sq(t2,t2);
+
+/* qhasm: z_40_0 = z_40_20*z_20_0 */
+/* asm 1: fe_mul(>z_40_0=fe#2,<z_40_20=fe#3,<z_20_0=fe#2); */
+/* asm 2: fe_mul(>z_40_0=t1,<z_40_20=t2,<z_20_0=t1); */
+fe_mul(t1,t2,t1);
+
+/* qhasm: z_50_10 = z_40_0^2^10 */
+/* asm 1: fe_sq(>z_50_10=fe#2,<z_40_0=fe#2); for (i = 1;i < 10;++i) fe_sq(>z_50_10=fe#2,>z_50_10=fe#2); */
+/* asm 2: fe_sq(>z_50_10=t1,<z_40_0=t1); for (i = 1;i < 10;++i) fe_sq(>z_50_10=t1,>z_50_10=t1); */
+fe_sq(t1,t1); for (i = 1;i < 10;++i) fe_sq(t1,t1);
+
+/* qhasm: z_50_0 = z_50_10*z_10_0 */
+/* asm 1: fe_mul(>z_50_0=fe#1,<z_50_10=fe#2,<z_10_0=fe#1); */
+/* asm 2: fe_mul(>z_50_0=t0,<z_50_10=t1,<z_10_0=t0); */
+fe_mul(t0,t1,t0);
+
+/* qhasm: z_100_50 = z_50_0^2^50 */
+/* asm 1: fe_sq(>z_100_50=fe#2,<z_50_0=fe#1); for (i = 1;i < 50;++i) fe_sq(>z_100_50=fe#2,>z_100_50=fe#2); */
+/* asm 2: fe_sq(>z_100_50=t1,<z_50_0=t0); for (i = 1;i < 50;++i) fe_sq(>z_100_50=t1,>z_100_50=t1); */
+fe_sq(t1,t0); for (i = 1;i < 50;++i) fe_sq(t1,t1);
+
+/* qhasm: z_100_0 = z_100_50*z_50_0 */
+/* asm 1: fe_mul(>z_100_0=fe#2,<z_100_50=fe#2,<z_50_0=fe#1); */
+/* asm 2: fe_mul(>z_100_0=t1,<z_100_50=t1,<z_50_0=t0); */
+fe_mul(t1,t1,t0);
+
+/* qhasm: z_200_100 = z_100_0^2^100 */
+/* asm 1: fe_sq(>z_200_100=fe#3,<z_100_0=fe#2); for (i = 1;i < 100;++i) fe_sq(>z_200_100=fe#3,>z_200_100=fe#3); */
+/* asm 2: fe_sq(>z_200_100=t2,<z_100_0=t1); for (i = 1;i < 100;++i) fe_sq(>z_200_100=t2,>z_200_100=t2); */
+fe_sq(t2,t1); for (i = 1;i < 100;++i) fe_sq(t2,t2);
+
+/* qhasm: z_200_0 = z_200_100*z_100_0 */
+/* asm 1: fe_mul(>z_200_0=fe#2,<z_200_100=fe#3,<z_100_0=fe#2); */
+/* asm 2: fe_mul(>z_200_0=t1,<z_200_100=t2,<z_100_0=t1); */
+fe_mul(t1,t2,t1);
+
+/* qhasm: z_250_50 = z_200_0^2^50 */
+/* asm 1: fe_sq(>z_250_50=fe#2,<z_200_0=fe#2); for (i = 1;i < 50;++i) fe_sq(>z_250_50=fe#2,>z_250_50=fe#2); */
+/* asm 2: fe_sq(>z_250_50=t1,<z_200_0=t1); for (i = 1;i < 50;++i) fe_sq(>z_250_50=t1,>z_250_50=t1); */
+fe_sq(t1,t1); for (i = 1;i < 50;++i) fe_sq(t1,t1);
+
+/* qhasm: z_250_0 = z_250_50*z_50_0 */
+/* asm 1: fe_mul(>z_250_0=fe#1,<z_250_50=fe#2,<z_50_0=fe#1); */
+/* asm 2: fe_mul(>z_250_0=t0,<z_250_50=t1,<z_50_0=t0); */
+fe_mul(t0,t1,t0);
+
+/* qhasm: z_252_2 = z_250_0^2^2 */
+/* asm 1: fe_sq(>z_252_2=fe#1,<z_250_0=fe#1); for (i = 1;i < 2;++i) fe_sq(>z_252_2=fe#1,>z_252_2=fe#1); */
+/* asm 2: fe_sq(>z_252_2=t0,<z_250_0=t0); for (i = 1;i < 2;++i) fe_sq(>z_252_2=t0,>z_252_2=t0); */
+fe_sq(t0,t0); for (i = 1;i < 2;++i) fe_sq(t0,t0);
+
+/* qhasm: z_252_3 = z_252_2*z1 */
+/* asm 1: fe_mul(>z_252_3=fe#12,<z_252_2=fe#1,<z1=fe#11); */
+/* asm 2: fe_mul(>z_252_3=out,<z_252_2=t0,<z1=z); */
+fe_mul(out,t0,z);
+
+/* qhasm: return */
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/pow22523.q b/crypt/monero_crypto/crypto_ops_builder/ref10/pow22523.q
new file mode 100644
index 0000000000..2ce1da9d4d
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/pow22523.q
@@ -0,0 +1,61 @@
+:name:fe:t0:t1:t2:t3:t4:t5:t6:t7:t8:t9:z:out:
+fe r:var/r=fe:
+
+enter f:enter/f:>z1=fe#11:
+return:nofallthrough:<z_252_3=fe#12:leave:
+
+h=f*g:<f=fe:<g=fe:>h=fe:asm/fe_mul(>h,<f,<g);:
+h=f^2^k:<f=fe:>h=fe:#k:asm/fe_sq(>h,<f); for (i = 1;i !lt; #k;++i) fe_sq(>h,>h);:
+
+:
+
+fe z1
+fe z2
+fe z8
+fe z9
+fe z11
+fe z22
+fe z_5_0
+fe z_10_5
+fe z_10_0
+fe z_20_10
+fe z_20_0
+fe z_40_20
+fe z_40_0
+fe z_50_10
+fe z_50_0
+fe z_100_50
+fe z_100_0
+fe z_200_100
+fe z_200_0
+fe z_250_50
+fe z_250_0
+fe z_252_2
+fe z_252_3
+
+enter pow22523
+
+z2 = z1^2^1
+z8 = z2^2^2
+z9 = z1*z8
+z11 = z2*z9
+z22 = z11^2^1
+z_5_0 = z9*z22
+z_10_5 = z_5_0^2^5
+z_10_0 = z_10_5*z_5_0
+z_20_10 = z_10_0^2^10
+z_20_0 = z_20_10*z_10_0
+z_40_20 = z_20_0^2^20
+z_40_0 = z_40_20*z_20_0
+z_50_10 = z_40_0^2^10
+z_50_0 = z_50_10*z_10_0
+z_100_50 = z_50_0^2^50
+z_100_0 = z_100_50*z_50_0
+z_200_100 = z_100_0^2^100
+z_200_0 = z_200_100*z_100_0
+z_250_50 = z_200_0^2^50
+z_250_0 = z_250_50*z_50_0
+z_252_2 = z_250_0^2^2
+z_252_3 = z_252_2*z1
+
+return
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/pow225521.h b/crypt/monero_crypto/crypto_ops_builder/ref10/pow225521.h
new file mode 100644
index 0000000000..109df779a2
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/pow225521.h
@@ -0,0 +1,160 @@
+
+/* qhasm: fe z1 */
+
+/* qhasm: fe z2 */
+
+/* qhasm: fe z8 */
+
+/* qhasm: fe z9 */
+
+/* qhasm: fe z11 */
+
+/* qhasm: fe z22 */
+
+/* qhasm: fe z_5_0 */
+
+/* qhasm: fe z_10_5 */
+
+/* qhasm: fe z_10_0 */
+
+/* qhasm: fe z_20_10 */
+
+/* qhasm: fe z_20_0 */
+
+/* qhasm: fe z_40_20 */
+
+/* qhasm: fe z_40_0 */
+
+/* qhasm: fe z_50_10 */
+
+/* qhasm: fe z_50_0 */
+
+/* qhasm: fe z_100_50 */
+
+/* qhasm: fe z_100_0 */
+
+/* qhasm: fe z_200_100 */
+
+/* qhasm: fe z_200_0 */
+
+/* qhasm: fe z_250_50 */
+
+/* qhasm: fe z_250_0 */
+
+/* qhasm: fe z_255_5 */
+
+/* qhasm: fe z_255_21 */
+
+/* qhasm: enter pow225521 */
+
+/* qhasm: z2 = z1^2^1 */
+/* asm 1: fe_sq(>z2=fe#1,<z1=fe#11); for (i = 1;i < 1;++i) fe_sq(>z2=fe#1,>z2=fe#1); */
+/* asm 2: fe_sq(>z2=t0,<z1=z); for (i = 1;i < 1;++i) fe_sq(>z2=t0,>z2=t0); */
+fe_sq(t0,z); for (i = 1;i < 1;++i) fe_sq(t0,t0);
+
+/* qhasm: z8 = z2^2^2 */
+/* asm 1: fe_sq(>z8=fe#2,<z2=fe#1); for (i = 1;i < 2;++i) fe_sq(>z8=fe#2,>z8=fe#2); */
+/* asm 2: fe_sq(>z8=t1,<z2=t0); for (i = 1;i < 2;++i) fe_sq(>z8=t1,>z8=t1); */
+fe_sq(t1,t0); for (i = 1;i < 2;++i) fe_sq(t1,t1);
+
+/* qhasm: z9 = z1*z8 */
+/* asm 1: fe_mul(>z9=fe#2,<z1=fe#11,<z8=fe#2); */
+/* asm 2: fe_mul(>z9=t1,<z1=z,<z8=t1); */
+fe_mul(t1,z,t1);
+
+/* qhasm: z11 = z2*z9 */
+/* asm 1: fe_mul(>z11=fe#1,<z2=fe#1,<z9=fe#2); */
+/* asm 2: fe_mul(>z11=t0,<z2=t0,<z9=t1); */
+fe_mul(t0,t0,t1);
+
+/* qhasm: z22 = z11^2^1 */
+/* asm 1: fe_sq(>z22=fe#3,<z11=fe#1); for (i = 1;i < 1;++i) fe_sq(>z22=fe#3,>z22=fe#3); */
+/* asm 2: fe_sq(>z22=t2,<z11=t0); for (i = 1;i < 1;++i) fe_sq(>z22=t2,>z22=t2); */
+fe_sq(t2,t0); for (i = 1;i < 1;++i) fe_sq(t2,t2);
+
+/* qhasm: z_5_0 = z9*z22 */
+/* asm 1: fe_mul(>z_5_0=fe#2,<z9=fe#2,<z22=fe#3); */
+/* asm 2: fe_mul(>z_5_0=t1,<z9=t1,<z22=t2); */
+fe_mul(t1,t1,t2);
+
+/* qhasm: z_10_5 = z_5_0^2^5 */
+/* asm 1: fe_sq(>z_10_5=fe#3,<z_5_0=fe#2); for (i = 1;i < 5;++i) fe_sq(>z_10_5=fe#3,>z_10_5=fe#3); */
+/* asm 2: fe_sq(>z_10_5=t2,<z_5_0=t1); for (i = 1;i < 5;++i) fe_sq(>z_10_5=t2,>z_10_5=t2); */
+fe_sq(t2,t1); for (i = 1;i < 5;++i) fe_sq(t2,t2);
+
+/* qhasm: z_10_0 = z_10_5*z_5_0 */
+/* asm 1: fe_mul(>z_10_0=fe#2,<z_10_5=fe#3,<z_5_0=fe#2); */
+/* asm 2: fe_mul(>z_10_0=t1,<z_10_5=t2,<z_5_0=t1); */
+fe_mul(t1,t2,t1);
+
+/* qhasm: z_20_10 = z_10_0^2^10 */
+/* asm 1: fe_sq(>z_20_10=fe#3,<z_10_0=fe#2); for (i = 1;i < 10;++i) fe_sq(>z_20_10=fe#3,>z_20_10=fe#3); */
+/* asm 2: fe_sq(>z_20_10=t2,<z_10_0=t1); for (i = 1;i < 10;++i) fe_sq(>z_20_10=t2,>z_20_10=t2); */
+fe_sq(t2,t1); for (i = 1;i < 10;++i) fe_sq(t2,t2);
+
+/* qhasm: z_20_0 = z_20_10*z_10_0 */
+/* asm 1: fe_mul(>z_20_0=fe#3,<z_20_10=fe#3,<z_10_0=fe#2); */
+/* asm 2: fe_mul(>z_20_0=t2,<z_20_10=t2,<z_10_0=t1); */
+fe_mul(t2,t2,t1);
+
+/* qhasm: z_40_20 = z_20_0^2^20 */
+/* asm 1: fe_sq(>z_40_20=fe#4,<z_20_0=fe#3); for (i = 1;i < 20;++i) fe_sq(>z_40_20=fe#4,>z_40_20=fe#4); */
+/* asm 2: fe_sq(>z_40_20=t3,<z_20_0=t2); for (i = 1;i < 20;++i) fe_sq(>z_40_20=t3,>z_40_20=t3); */
+fe_sq(t3,t2); for (i = 1;i < 20;++i) fe_sq(t3,t3);
+
+/* qhasm: z_40_0 = z_40_20*z_20_0 */
+/* asm 1: fe_mul(>z_40_0=fe#3,<z_40_20=fe#4,<z_20_0=fe#3); */
+/* asm 2: fe_mul(>z_40_0=t2,<z_40_20=t3,<z_20_0=t2); */
+fe_mul(t2,t3,t2);
+
+/* qhasm: z_50_10 = z_40_0^2^10 */
+/* asm 1: fe_sq(>z_50_10=fe#3,<z_40_0=fe#3); for (i = 1;i < 10;++i) fe_sq(>z_50_10=fe#3,>z_50_10=fe#3); */
+/* asm 2: fe_sq(>z_50_10=t2,<z_40_0=t2); for (i = 1;i < 10;++i) fe_sq(>z_50_10=t2,>z_50_10=t2); */
+fe_sq(t2,t2); for (i = 1;i < 10;++i) fe_sq(t2,t2);
+
+/* qhasm: z_50_0 = z_50_10*z_10_0 */
+/* asm 1: fe_mul(>z_50_0=fe#2,<z_50_10=fe#3,<z_10_0=fe#2); */
+/* asm 2: fe_mul(>z_50_0=t1,<z_50_10=t2,<z_10_0=t1); */
+fe_mul(t1,t2,t1);
+
+/* qhasm: z_100_50 = z_50_0^2^50 */
+/* asm 1: fe_sq(>z_100_50=fe#3,<z_50_0=fe#2); for (i = 1;i < 50;++i) fe_sq(>z_100_50=fe#3,>z_100_50=fe#3); */
+/* asm 2: fe_sq(>z_100_50=t2,<z_50_0=t1); for (i = 1;i < 50;++i) fe_sq(>z_100_50=t2,>z_100_50=t2); */
+fe_sq(t2,t1); for (i = 1;i < 50;++i) fe_sq(t2,t2);
+
+/* qhasm: z_100_0 = z_100_50*z_50_0 */
+/* asm 1: fe_mul(>z_100_0=fe#3,<z_100_50=fe#3,<z_50_0=fe#2); */
+/* asm 2: fe_mul(>z_100_0=t2,<z_100_50=t2,<z_50_0=t1); */
+fe_mul(t2,t2,t1);
+
+/* qhasm: z_200_100 = z_100_0^2^100 */
+/* asm 1: fe_sq(>z_200_100=fe#4,<z_100_0=fe#3); for (i = 1;i < 100;++i) fe_sq(>z_200_100=fe#4,>z_200_100=fe#4); */
+/* asm 2: fe_sq(>z_200_100=t3,<z_100_0=t2); for (i = 1;i < 100;++i) fe_sq(>z_200_100=t3,>z_200_100=t3); */
+fe_sq(t3,t2); for (i = 1;i < 100;++i) fe_sq(t3,t3);
+
+/* qhasm: z_200_0 = z_200_100*z_100_0 */
+/* asm 1: fe_mul(>z_200_0=fe#3,<z_200_100=fe#4,<z_100_0=fe#3); */
+/* asm 2: fe_mul(>z_200_0=t2,<z_200_100=t3,<z_100_0=t2); */
+fe_mul(t2,t3,t2);
+
+/* qhasm: z_250_50 = z_200_0^2^50 */
+/* asm 1: fe_sq(>z_250_50=fe#3,<z_200_0=fe#3); for (i = 1;i < 50;++i) fe_sq(>z_250_50=fe#3,>z_250_50=fe#3); */
+/* asm 2: fe_sq(>z_250_50=t2,<z_200_0=t2); for (i = 1;i < 50;++i) fe_sq(>z_250_50=t2,>z_250_50=t2); */
+fe_sq(t2,t2); for (i = 1;i < 50;++i) fe_sq(t2,t2);
+
+/* qhasm: z_250_0 = z_250_50*z_50_0 */
+/* asm 1: fe_mul(>z_250_0=fe#2,<z_250_50=fe#3,<z_50_0=fe#2); */
+/* asm 2: fe_mul(>z_250_0=t1,<z_250_50=t2,<z_50_0=t1); */
+fe_mul(t1,t2,t1);
+
+/* qhasm: z_255_5 = z_250_0^2^5 */
+/* asm 1: fe_sq(>z_255_5=fe#2,<z_250_0=fe#2); for (i = 1;i < 5;++i) fe_sq(>z_255_5=fe#2,>z_255_5=fe#2); */
+/* asm 2: fe_sq(>z_255_5=t1,<z_250_0=t1); for (i = 1;i < 5;++i) fe_sq(>z_255_5=t1,>z_255_5=t1); */
+fe_sq(t1,t1); for (i = 1;i < 5;++i) fe_sq(t1,t1);
+
+/* qhasm: z_255_21 = z_255_5*z11 */
+/* asm 1: fe_mul(>z_255_21=fe#12,<z_255_5=fe#2,<z11=fe#1); */
+/* asm 2: fe_mul(>z_255_21=out,<z_255_5=t1,<z11=t0); */
+fe_mul(out,t1,t0);
+
+/* qhasm: return */
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/pow225521.q b/crypt/monero_crypto/crypto_ops_builder/ref10/pow225521.q
new file mode 100644
index 0000000000..45be57c08a
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/pow225521.q
@@ -0,0 +1,61 @@
+:name:fe:t0:t1:t2:t3:t4:t5:t6:t7:t8:t9:z:out:
+fe r:var/r=fe:
+
+enter f:enter/f:>z1=fe#11:
+return:nofallthrough:<z_255_21=fe#12:leave:
+
+h=f*g:<f=fe:<g=fe:>h=fe:asm/fe_mul(>h,<f,<g);:
+h=f^2^k:<f=fe:>h=fe:#k:asm/fe_sq(>h,<f); for (i = 1;i !lt; #k;++i) fe_sq(>h,>h);:
+
+:
+
+fe z1
+fe z2
+fe z8
+fe z9
+fe z11
+fe z22
+fe z_5_0
+fe z_10_5
+fe z_10_0
+fe z_20_10
+fe z_20_0
+fe z_40_20
+fe z_40_0
+fe z_50_10
+fe z_50_0
+fe z_100_50
+fe z_100_0
+fe z_200_100
+fe z_200_0
+fe z_250_50
+fe z_250_0
+fe z_255_5
+fe z_255_21
+
+enter pow225521
+
+z2 = z1^2^1
+z8 = z2^2^2
+z9 = z1*z8
+z11 = z2*z9
+z22 = z11^2^1
+z_5_0 = z9*z22
+z_10_5 = z_5_0^2^5
+z_10_0 = z_10_5*z_5_0
+z_20_10 = z_10_0^2^10
+z_20_0 = z_20_10*z_10_0
+z_40_20 = z_20_0^2^20
+z_40_0 = z_40_20*z_20_0
+z_50_10 = z_40_0^2^10
+z_50_0 = z_50_10*z_10_0
+z_100_50 = z_50_0^2^50
+z_100_0 = z_100_50*z_50_0
+z_200_100 = z_100_0^2^100
+z_200_0 = z_200_100*z_100_0
+z_250_50 = z_200_0^2^50
+z_250_0 = z_250_50*z_50_0
+z_255_5 = z_250_0^2^5
+z_255_21 = z_255_5*z11
+
+return
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/q2h.sh b/crypt/monero_crypto/crypto_ops_builder/ref10/q2h.sh
new file mode 100644
index 0000000000..47ec5110e8
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/q2h.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+sed 's/^#.*//' \
+| qhasm-generic \
+| sed 's_//\(.*\)$_/*\1 */_'
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/sc.h b/crypt/monero_crypto/crypto_ops_builder/ref10/sc.h
new file mode 100644
index 0000000000..d32ed2e8ca
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/sc.h
@@ -0,0 +1,15 @@
+#ifndef SC_H
+#define SC_H
+
+/*
+The set of scalars is \Z/l
+where l = 2^252 + 27742317777372353535851937790883648493.
+*/
+
+#define sc_reduce crypto_sign_ed25519_ref10_sc_reduce
+#define sc_muladd crypto_sign_ed25519_ref10_sc_muladd
+
+extern void sc_reduce(unsigned char *);
+extern void sc_muladd(unsigned char *,const unsigned char *,const unsigned char *,const unsigned char *);
+
+#endif
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/sc_muladd.c b/crypt/monero_crypto/crypto_ops_builder/ref10/sc_muladd.c
new file mode 100644
index 0000000000..6f1e9d02d6
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/sc_muladd.c
@@ -0,0 +1,368 @@
+#include "sc.h"
+#include "crypto_int64.h"
+#include "crypto_uint32.h"
+#include "crypto_uint64.h"
+
+static crypto_uint64 load_3(const unsigned char *in)
+{
+  crypto_uint64 result;
+  result = (crypto_uint64) in[0];
+  result |= ((crypto_uint64) in[1]) << 8;
+  result |= ((crypto_uint64) in[2]) << 16;
+  return result;
+}
+
+static crypto_uint64 load_4(const unsigned char *in)
+{
+  crypto_uint64 result;
+  result = (crypto_uint64) in[0];
+  result |= ((crypto_uint64) in[1]) << 8;
+  result |= ((crypto_uint64) in[2]) << 16;
+  result |= ((crypto_uint64) in[3]) << 24;
+  return result;
+}
+
+/*
+Input:
+  a[0]+256*a[1]+...+256^31*a[31] = a
+  b[0]+256*b[1]+...+256^31*b[31] = b
+  c[0]+256*c[1]+...+256^31*c[31] = c
+
+Output:
+  s[0]+256*s[1]+...+256^31*s[31] = (ab+c) mod l
+  where l = 2^252 + 27742317777372353535851937790883648493.
+*/
+
+void sc_muladd(unsigned char *s,const unsigned char *a,const unsigned char *b,const unsigned char *c)
+{
+  crypto_int64 a0 = 2097151 & load_3(a);
+  crypto_int64 a1 = 2097151 & (load_4(a + 2) >> 5);
+  crypto_int64 a2 = 2097151 & (load_3(a + 5) >> 2);
+  crypto_int64 a3 = 2097151 & (load_4(a + 7) >> 7);
+  crypto_int64 a4 = 2097151 & (load_4(a + 10) >> 4);
+  crypto_int64 a5 = 2097151 & (load_3(a + 13) >> 1);
+  crypto_int64 a6 = 2097151 & (load_4(a + 15) >> 6);
+  crypto_int64 a7 = 2097151 & (load_3(a + 18) >> 3);
+  crypto_int64 a8 = 2097151 & load_3(a + 21);
+  crypto_int64 a9 = 2097151 & (load_4(a + 23) >> 5);
+  crypto_int64 a10 = 2097151 & (load_3(a + 26) >> 2);
+  crypto_int64 a11 = (load_4(a + 28) >> 7);
+  crypto_int64 b0 = 2097151 & load_3(b);
+  crypto_int64 b1 = 2097151 & (load_4(b + 2) >> 5);
+  crypto_int64 b2 = 2097151 & (load_3(b + 5) >> 2);
+  crypto_int64 b3 = 2097151 & (load_4(b + 7) >> 7);
+  crypto_int64 b4 = 2097151 & (load_4(b + 10) >> 4);
+  crypto_int64 b5 = 2097151 & (load_3(b + 13) >> 1);
+  crypto_int64 b6 = 2097151 & (load_4(b + 15) >> 6);
+  crypto_int64 b7 = 2097151 & (load_3(b + 18) >> 3);
+  crypto_int64 b8 = 2097151 & load_3(b + 21);
+  crypto_int64 b9 = 2097151 & (load_4(b + 23) >> 5);
+  crypto_int64 b10 = 2097151 & (load_3(b + 26) >> 2);
+  crypto_int64 b11 = (load_4(b + 28) >> 7);
+  crypto_int64 c0 = 2097151 & load_3(c);
+  crypto_int64 c1 = 2097151 & (load_4(c + 2) >> 5);
+  crypto_int64 c2 = 2097151 & (load_3(c + 5) >> 2);
+  crypto_int64 c3 = 2097151 & (load_4(c + 7) >> 7);
+  crypto_int64 c4 = 2097151 & (load_4(c + 10) >> 4);
+  crypto_int64 c5 = 2097151 & (load_3(c + 13) >> 1);
+  crypto_int64 c6 = 2097151 & (load_4(c + 15) >> 6);
+  crypto_int64 c7 = 2097151 & (load_3(c + 18) >> 3);
+  crypto_int64 c8 = 2097151 & load_3(c + 21);
+  crypto_int64 c9 = 2097151 & (load_4(c + 23) >> 5);
+  crypto_int64 c10 = 2097151 & (load_3(c + 26) >> 2);
+  crypto_int64 c11 = (load_4(c + 28) >> 7);
+  crypto_int64 s0;
+  crypto_int64 s1;
+  crypto_int64 s2;
+  crypto_int64 s3;
+  crypto_int64 s4;
+  crypto_int64 s5;
+  crypto_int64 s6;
+  crypto_int64 s7;
+  crypto_int64 s8;
+  crypto_int64 s9;
+  crypto_int64 s10;
+  crypto_int64 s11;
+  crypto_int64 s12;
+  crypto_int64 s13;
+  crypto_int64 s14;
+  crypto_int64 s15;
+  crypto_int64 s16;
+  crypto_int64 s17;
+  crypto_int64 s18;
+  crypto_int64 s19;
+  crypto_int64 s20;
+  crypto_int64 s21;
+  crypto_int64 s22;
+  crypto_int64 s23;
+  crypto_int64 carry0;
+  crypto_int64 carry1;
+  crypto_int64 carry2;
+  crypto_int64 carry3;
+  crypto_int64 carry4;
+  crypto_int64 carry5;
+  crypto_int64 carry6;
+  crypto_int64 carry7;
+  crypto_int64 carry8;
+  crypto_int64 carry9;
+  crypto_int64 carry10;
+  crypto_int64 carry11;
+  crypto_int64 carry12;
+  crypto_int64 carry13;
+  crypto_int64 carry14;
+  crypto_int64 carry15;
+  crypto_int64 carry16;
+  crypto_int64 carry17;
+  crypto_int64 carry18;
+  crypto_int64 carry19;
+  crypto_int64 carry20;
+  crypto_int64 carry21;
+  crypto_int64 carry22;
+
+  s0 = c0 + a0*b0;
+  s1 = c1 + a0*b1 + a1*b0;
+  s2 = c2 + a0*b2 + a1*b1 + a2*b0;
+  s3 = c3 + a0*b3 + a1*b2 + a2*b1 + a3*b0;
+  s4 = c4 + a0*b4 + a1*b3 + a2*b2 + a3*b1 + a4*b0;
+  s5 = c5 + a0*b5 + a1*b4 + a2*b3 + a3*b2 + a4*b1 + a5*b0;
+  s6 = c6 + a0*b6 + a1*b5 + a2*b4 + a3*b3 + a4*b2 + a5*b1 + a6*b0;
+  s7 = c7 + a0*b7 + a1*b6 + a2*b5 + a3*b4 + a4*b3 + a5*b2 + a6*b1 + a7*b0;
+  s8 = c8 + a0*b8 + a1*b7 + a2*b6 + a3*b5 + a4*b4 + a5*b3 + a6*b2 + a7*b1 + a8*b0;
+  s9 = c9 + a0*b9 + a1*b8 + a2*b7 + a3*b6 + a4*b5 + a5*b4 + a6*b3 + a7*b2 + a8*b1 + a9*b0;
+  s10 = c10 + a0*b10 + a1*b9 + a2*b8 + a3*b7 + a4*b6 + a5*b5 + a6*b4 + a7*b3 + a8*b2 + a9*b1 + a10*b0;
+  s11 = c11 + a0*b11 + a1*b10 + a2*b9 + a3*b8 + a4*b7 + a5*b6 + a6*b5 + a7*b4 + a8*b3 + a9*b2 + a10*b1 + a11*b0;
+  s12 = a1*b11 + a2*b10 + a3*b9 + a4*b8 + a5*b7 + a6*b6 + a7*b5 + a8*b4 + a9*b3 + a10*b2 + a11*b1;
+  s13 = a2*b11 + a3*b10 + a4*b9 + a5*b8 + a6*b7 + a7*b6 + a8*b5 + a9*b4 + a10*b3 + a11*b2;
+  s14 = a3*b11 + a4*b10 + a5*b9 + a6*b8 + a7*b7 + a8*b6 + a9*b5 + a10*b4 + a11*b3;
+  s15 = a4*b11 + a5*b10 + a6*b9 + a7*b8 + a8*b7 + a9*b6 + a10*b5 + a11*b4;
+  s16 = a5*b11 + a6*b10 + a7*b9 + a8*b8 + a9*b7 + a10*b6 + a11*b5;
+  s17 = a6*b11 + a7*b10 + a8*b9 + a9*b8 + a10*b7 + a11*b6;
+  s18 = a7*b11 + a8*b10 + a9*b9 + a10*b8 + a11*b7;
+  s19 = a8*b11 + a9*b10 + a10*b9 + a11*b8;
+  s20 = a9*b11 + a10*b10 + a11*b9;
+  s21 = a10*b11 + a11*b10;
+  s22 = a11*b11;
+  s23 = 0;
+
+  carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
+  carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
+  carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
+  carry18 = (s18 + (1<<20)) >> 21; s19 += carry18; s18 -= carry18 << 21;
+  carry20 = (s20 + (1<<20)) >> 21; s21 += carry20; s20 -= carry20 << 21;
+  carry22 = (s22 + (1<<20)) >> 21; s23 += carry22; s22 -= carry22 << 21;
+
+  carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+  carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
+  carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
+  carry17 = (s17 + (1<<20)) >> 21; s18 += carry17; s17 -= carry17 << 21;
+  carry19 = (s19 + (1<<20)) >> 21; s20 += carry19; s19 -= carry19 << 21;
+  carry21 = (s21 + (1<<20)) >> 21; s22 += carry21; s21 -= carry21 << 21;
+
+  s11 += s23 * 666643;
+  s12 += s23 * 470296;
+  s13 += s23 * 654183;
+  s14 -= s23 * 997805;
+  s15 += s23 * 136657;
+  s16 -= s23 * 683901;
+  s23 = 0;
+
+  s10 += s22 * 666643;
+  s11 += s22 * 470296;
+  s12 += s22 * 654183;
+  s13 -= s22 * 997805;
+  s14 += s22 * 136657;
+  s15 -= s22 * 683901;
+  s22 = 0;
+
+  s9 += s21 * 666643;
+  s10 += s21 * 470296;
+  s11 += s21 * 654183;
+  s12 -= s21 * 997805;
+  s13 += s21 * 136657;
+  s14 -= s21 * 683901;
+  s21 = 0;
+
+  s8 += s20 * 666643;
+  s9 += s20 * 470296;
+  s10 += s20 * 654183;
+  s11 -= s20 * 997805;
+  s12 += s20 * 136657;
+  s13 -= s20 * 683901;
+  s20 = 0;
+
+  s7 += s19 * 666643;
+  s8 += s19 * 470296;
+  s9 += s19 * 654183;
+  s10 -= s19 * 997805;
+  s11 += s19 * 136657;
+  s12 -= s19 * 683901;
+  s19 = 0;
+
+  s6 += s18 * 666643;
+  s7 += s18 * 470296;
+  s8 += s18 * 654183;
+  s9 -= s18 * 997805;
+  s10 += s18 * 136657;
+  s11 -= s18 * 683901;
+  s18 = 0;
+
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
+  carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
+  carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
+
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+  carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
+  carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
+
+  s5 += s17 * 666643;
+  s6 += s17 * 470296;
+  s7 += s17 * 654183;
+  s8 -= s17 * 997805;
+  s9 += s17 * 136657;
+  s10 -= s17 * 683901;
+  s17 = 0;
+
+  s4 += s16 * 666643;
+  s5 += s16 * 470296;
+  s6 += s16 * 654183;
+  s7 -= s16 * 997805;
+  s8 += s16 * 136657;
+  s9 -= s16 * 683901;
+  s16 = 0;
+
+  s3 += s15 * 666643;
+  s4 += s15 * 470296;
+  s5 += s15 * 654183;
+  s6 -= s15 * 997805;
+  s7 += s15 * 136657;
+  s8 -= s15 * 683901;
+  s15 = 0;
+
+  s2 += s14 * 666643;
+  s3 += s14 * 470296;
+  s4 += s14 * 654183;
+  s5 -= s14 * 997805;
+  s6 += s14 * 136657;
+  s7 -= s14 * 683901;
+  s14 = 0;
+
+  s1 += s13 * 666643;
+  s2 += s13 * 470296;
+  s3 += s13 * 654183;
+  s4 -= s13 * 997805;
+  s5 += s13 * 136657;
+  s6 -= s13 * 683901;
+  s13 = 0;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  s[0] = s0 >> 0;
+  s[1] = s0 >> 8;
+  s[2] = (s0 >> 16) | (s1 << 5);
+  s[3] = s1 >> 3;
+  s[4] = s1 >> 11;
+  s[5] = (s1 >> 19) | (s2 << 2);
+  s[6] = s2 >> 6;
+  s[7] = (s2 >> 14) | (s3 << 7);
+  s[8] = s3 >> 1;
+  s[9] = s3 >> 9;
+  s[10] = (s3 >> 17) | (s4 << 4);
+  s[11] = s4 >> 4;
+  s[12] = s4 >> 12;
+  s[13] = (s4 >> 20) | (s5 << 1);
+  s[14] = s5 >> 7;
+  s[15] = (s5 >> 15) | (s6 << 6);
+  s[16] = s6 >> 2;
+  s[17] = s6 >> 10;
+  s[18] = (s6 >> 18) | (s7 << 3);
+  s[19] = s7 >> 5;
+  s[20] = s7 >> 13;
+  s[21] = s8 >> 0;
+  s[22] = s8 >> 8;
+  s[23] = (s8 >> 16) | (s9 << 5);
+  s[24] = s9 >> 3;
+  s[25] = s9 >> 11;
+  s[26] = (s9 >> 19) | (s10 << 2);
+  s[27] = s10 >> 6;
+  s[28] = (s10 >> 14) | (s11 << 7);
+  s[29] = s11 >> 1;
+  s[30] = s11 >> 9;
+  s[31] = s11 >> 17;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/sc_reduce.c b/crypt/monero_crypto/crypto_ops_builder/ref10/sc_reduce.c
new file mode 100644
index 0000000000..d01f5a5737
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/sc_reduce.c
@@ -0,0 +1,275 @@
+#include "sc.h"
+#include "crypto_int64.h"
+#include "crypto_uint32.h"
+#include "crypto_uint64.h"
+
+static crypto_uint64 load_3(const unsigned char *in)
+{
+  crypto_uint64 result;
+  result = (crypto_uint64) in[0];
+  result |= ((crypto_uint64) in[1]) << 8;
+  result |= ((crypto_uint64) in[2]) << 16;
+  return result;
+}
+
+static crypto_uint64 load_4(const unsigned char *in)
+{
+  crypto_uint64 result;
+  result = (crypto_uint64) in[0];
+  result |= ((crypto_uint64) in[1]) << 8;
+  result |= ((crypto_uint64) in[2]) << 16;
+  result |= ((crypto_uint64) in[3]) << 24;
+  return result;
+}
+
+/*
+Input:
+  s[0]+256*s[1]+...+256^63*s[63] = s
+
+Output:
+  s[0]+256*s[1]+...+256^31*s[31] = s mod l
+  where l = 2^252 + 27742317777372353535851937790883648493.
+  Overwrites s in place.
+*/
+
+void sc_reduce(unsigned char *s)
+{
+  crypto_int64 s0 = 2097151 & load_3(s);
+  crypto_int64 s1 = 2097151 & (load_4(s + 2) >> 5);
+  crypto_int64 s2 = 2097151 & (load_3(s + 5) >> 2);
+  crypto_int64 s3 = 2097151 & (load_4(s + 7) >> 7);
+  crypto_int64 s4 = 2097151 & (load_4(s + 10) >> 4);
+  crypto_int64 s5 = 2097151 & (load_3(s + 13) >> 1);
+  crypto_int64 s6 = 2097151 & (load_4(s + 15) >> 6);
+  crypto_int64 s7 = 2097151 & (load_3(s + 18) >> 3);
+  crypto_int64 s8 = 2097151 & load_3(s + 21);
+  crypto_int64 s9 = 2097151 & (load_4(s + 23) >> 5);
+  crypto_int64 s10 = 2097151 & (load_3(s + 26) >> 2);
+  crypto_int64 s11 = 2097151 & (load_4(s + 28) >> 7);
+  crypto_int64 s12 = 2097151 & (load_4(s + 31) >> 4);
+  crypto_int64 s13 = 2097151 & (load_3(s + 34) >> 1);
+  crypto_int64 s14 = 2097151 & (load_4(s + 36) >> 6);
+  crypto_int64 s15 = 2097151 & (load_3(s + 39) >> 3);
+  crypto_int64 s16 = 2097151 & load_3(s + 42);
+  crypto_int64 s17 = 2097151 & (load_4(s + 44) >> 5);
+  crypto_int64 s18 = 2097151 & (load_3(s + 47) >> 2);
+  crypto_int64 s19 = 2097151 & (load_4(s + 49) >> 7);
+  crypto_int64 s20 = 2097151 & (load_4(s + 52) >> 4);
+  crypto_int64 s21 = 2097151 & (load_3(s + 55) >> 1);
+  crypto_int64 s22 = 2097151 & (load_4(s + 57) >> 6);
+  crypto_int64 s23 = (load_4(s + 60) >> 3);
+  crypto_int64 carry0;
+  crypto_int64 carry1;
+  crypto_int64 carry2;
+  crypto_int64 carry3;
+  crypto_int64 carry4;
+  crypto_int64 carry5;
+  crypto_int64 carry6;
+  crypto_int64 carry7;
+  crypto_int64 carry8;
+  crypto_int64 carry9;
+  crypto_int64 carry10;
+  crypto_int64 carry11;
+  crypto_int64 carry12;
+  crypto_int64 carry13;
+  crypto_int64 carry14;
+  crypto_int64 carry15;
+  crypto_int64 carry16;
+
+  s11 += s23 * 666643;
+  s12 += s23 * 470296;
+  s13 += s23 * 654183;
+  s14 -= s23 * 997805;
+  s15 += s23 * 136657;
+  s16 -= s23 * 683901;
+  s23 = 0;
+
+  s10 += s22 * 666643;
+  s11 += s22 * 470296;
+  s12 += s22 * 654183;
+  s13 -= s22 * 997805;
+  s14 += s22 * 136657;
+  s15 -= s22 * 683901;
+  s22 = 0;
+
+  s9 += s21 * 666643;
+  s10 += s21 * 470296;
+  s11 += s21 * 654183;
+  s12 -= s21 * 997805;
+  s13 += s21 * 136657;
+  s14 -= s21 * 683901;
+  s21 = 0;
+
+  s8 += s20 * 666643;
+  s9 += s20 * 470296;
+  s10 += s20 * 654183;
+  s11 -= s20 * 997805;
+  s12 += s20 * 136657;
+  s13 -= s20 * 683901;
+  s20 = 0;
+
+  s7 += s19 * 666643;
+  s8 += s19 * 470296;
+  s9 += s19 * 654183;
+  s10 -= s19 * 997805;
+  s11 += s19 * 136657;
+  s12 -= s19 * 683901;
+  s19 = 0;
+
+  s6 += s18 * 666643;
+  s7 += s18 * 470296;
+  s8 += s18 * 654183;
+  s9 -= s18 * 997805;
+  s10 += s18 * 136657;
+  s11 -= s18 * 683901;
+  s18 = 0;
+
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
+  carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
+  carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
+
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+  carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
+  carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
+
+  s5 += s17 * 666643;
+  s6 += s17 * 470296;
+  s7 += s17 * 654183;
+  s8 -= s17 * 997805;
+  s9 += s17 * 136657;
+  s10 -= s17 * 683901;
+  s17 = 0;
+
+  s4 += s16 * 666643;
+  s5 += s16 * 470296;
+  s6 += s16 * 654183;
+  s7 -= s16 * 997805;
+  s8 += s16 * 136657;
+  s9 -= s16 * 683901;
+  s16 = 0;
+
+  s3 += s15 * 666643;
+  s4 += s15 * 470296;
+  s5 += s15 * 654183;
+  s6 -= s15 * 997805;
+  s7 += s15 * 136657;
+  s8 -= s15 * 683901;
+  s15 = 0;
+
+  s2 += s14 * 666643;
+  s3 += s14 * 470296;
+  s4 += s14 * 654183;
+  s5 -= s14 * 997805;
+  s6 += s14 * 136657;
+  s7 -= s14 * 683901;
+  s14 = 0;
+
+  s1 += s13 * 666643;
+  s2 += s13 * 470296;
+  s3 += s13 * 654183;
+  s4 -= s13 * 997805;
+  s5 += s13 * 136657;
+  s6 -= s13 * 683901;
+  s13 = 0;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  s[0] = s0 >> 0;
+  s[1] = s0 >> 8;
+  s[2] = (s0 >> 16) | (s1 << 5);
+  s[3] = s1 >> 3;
+  s[4] = s1 >> 11;
+  s[5] = (s1 >> 19) | (s2 << 2);
+  s[6] = s2 >> 6;
+  s[7] = (s2 >> 14) | (s3 << 7);
+  s[8] = s3 >> 1;
+  s[9] = s3 >> 9;
+  s[10] = (s3 >> 17) | (s4 << 4);
+  s[11] = s4 >> 4;
+  s[12] = s4 >> 12;
+  s[13] = (s4 >> 20) | (s5 << 1);
+  s[14] = s5 >> 7;
+  s[15] = (s5 >> 15) | (s6 << 6);
+  s[16] = s6 >> 2;
+  s[17] = s6 >> 10;
+  s[18] = (s6 >> 18) | (s7 << 3);
+  s[19] = s7 >> 5;
+  s[20] = s7 >> 13;
+  s[21] = s8 >> 0;
+  s[22] = s8 >> 8;
+  s[23] = (s8 >> 16) | (s9 << 5);
+  s[24] = s9 >> 3;
+  s[25] = s9 >> 11;
+  s[26] = (s9 >> 19) | (s10 << 2);
+  s[27] = s10 >> 6;
+  s[28] = (s10 >> 14) | (s11 << 7);
+  s[29] = s11 >> 1;
+  s[30] = s11 >> 9;
+  s[31] = s11 >> 17;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/sign.c b/crypt/monero_crypto/crypto_ops_builder/ref10/sign.c
new file mode 100644
index 0000000000..de53742a6c
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/sign.c
@@ -0,0 +1,41 @@
+#include <string.h>
+#include "crypto_sign.h"
+#include "crypto_hash_sha512.h"
+#include "ge.h"
+#include "sc.h"
+
+int crypto_sign(
+  unsigned char *sm,unsigned long long *smlen,
+  const unsigned char *m,unsigned long long mlen,
+  const unsigned char *sk
+)
+{
+  unsigned char pk[32];
+  unsigned char az[64];
+  unsigned char nonce[64];
+  unsigned char hram[64];
+  ge_p3 R;
+
+  memmove(pk,sk + 32,32);
+
+  crypto_hash_sha512(az,sk,32);
+  az[0] &= 248;
+  az[31] &= 63;
+  az[31] |= 64;
+
+  *smlen = mlen + 64;
+  memmove(sm + 64,m,mlen);
+  memmove(sm + 32,az + 32,32);
+  crypto_hash_sha512(nonce,sm + 32,mlen + 32);
+  memmove(sm + 32,pk,32);
+
+  sc_reduce(nonce);
+  ge_scalarmult_base(&R,nonce);
+  ge_p3_tobytes(sm,&R);
+
+  crypto_hash_sha512(hram,sm,mlen + 64);
+  sc_reduce(hram);
+  sc_muladd(sm + 32,hram,az,nonce);
+
+  return 0;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/sqrtm1.h b/crypt/monero_crypto/crypto_ops_builder/ref10/sqrtm1.h
new file mode 100644
index 0000000000..d8caa23b6a
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/sqrtm1.h
@@ -0,0 +1 @@
+-32595792,-7943725,9377950,3500415,12389472,-272473,-25146209,-2005654,326686,11406482
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10/sqrtm1.py b/crypt/monero_crypto/crypto_ops_builder/ref10/sqrtm1.py
new file mode 100644
index 0000000000..9a47fbc12a
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10/sqrtm1.py
@@ -0,0 +1,28 @@
+q = 2**255 - 19
+
+def expmod(b,e,m):
+  if e == 0: return 1
+  t = expmod(b,e/2,m)**2 % m
+  if e & 1: t = (t*b) % m
+  return t
+
+def inv(x):
+  return expmod(x,q-2,q)
+
+def radix255(x):
+  x = x % q
+  if x + x > q: x -= q
+  x = [x,0,0,0,0,0,0,0,0,0]
+  bits = [26,25,26,25,26,25,26,25,26,25]
+  for i in range(9):
+    carry = (x[i] + 2**(bits[i]-1)) / 2**bits[i]
+    x[i] -= carry * 2**bits[i]
+    x[i + 1] += carry
+  result = ""
+  for i in range(9):
+    result = result+str(x[i])+","
+  result = result+str(x[9])
+  return result
+
+I = expmod(2,(q-1)/4,q)
+print radix255(I)
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/MakeCryptoOps.py b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/MakeCryptoOps.py
new file mode 100644
index 0000000000..5f8776a493
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/MakeCryptoOps.py
@@ -0,0 +1,261 @@
+#assumes you have gnu sed, osx sed might need slight syntax changeo
+#c.f. http://unix.stackexchange.com/questions/112023/how-can-i-replace-a-string-in-a-files
+
+#written by shen-noether monero research labs
+
+import os #for copying and sed etc.
+import glob #for copy files
+import textwrap #for comments etc
+
+print("make sure you have cat and grep installed")
+print("also assumes gnu sed syntax, c.f. :http://unix.stackexchange.com/questions/112023/how-can-i-replace-a-string-in-a-files")
+print("I believe osx may have slightly different version of sed")
+print("maybe someone smart can replace the sed with perl..")
+
+a = ""
+
+license = textwrap.dedent("""\
+    // 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
+    """)
+
+crypto_ops_includes = textwrap.dedent("""\
+    #include <assert.h>
+    #include <stdint.h>
+
+    #include "warnings.h"
+    #include "crypto-ops.h"
+
+    DISABLE_VS_WARNINGS(4146 4244)
+    """)
+
+predeclarations = textwrap.dedent("""\
+    /* Predeclarations */
+
+    static void fe_mul(fe, const fe, const fe);
+    static void fe_sq(fe, const fe);
+    static void fe_tobytes(unsigned char *, const fe);
+    static int fe_isnonzero(const fe); 
+    static void ge_madd(ge_p1p1 *, const ge_p3 *, const ge_precomp *);
+    static void ge_msub(ge_p1p1 *, const ge_p3 *, const ge_precomp *);
+    static void ge_p2_0(ge_p2 *);
+    static void ge_p3_dbl(ge_p1p1 *, const ge_p3 *);
+    static void ge_sub(ge_p1p1 *, const ge_p3 *, const ge_cached *);
+    static void fe_divpowm1(fe, const fe, const fe);
+    """)
+
+
+
+fe_comments = textwrap.dedent("""\
+    /*
+    fe means field element.
+    Here the field is \Z/(2^255-19).
+    An element t, entries t[0]...t[9], represents the integer
+    t[0]+2^26 t[1]+2^51 t[2]+2^77 t[3]+2^102 t[4]+...+2^230 t[9].
+    Bounds on each t[i] vary depending on context.
+    */
+    """)
+
+sc_comments = textwrap.dedent("""\
+    /*
+     *
+     * sc code
+     *
+     *
+    The set of scalars is \Z/l
+    where l = 2^252 + 27742317777372353535851937790883648493.
+
+    This is the order of the curve ed25519. 
+    The point is that if a is a scalar and P is a point,
+    and b is congruent to a mod l, then aP = bP.
+    Thus, reducing mod l can possibly give you a smaller scalar,
+    so your elliptic curve operations take less time
+    */
+    """)
+
+ge_comments = textwrap.dedent("""\
+    /*
+     *
+     * ge code
+     *
+     *
+    ge means group element.
+
+    Here the group is the set of pairs (x,y) of field elements (see fe.h)
+    satisfying -x^2 + y^2 = 1 + d x^2y^2
+    where d = -121665/121666.
+
+    Representations:
+      ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z
+      ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT
+      ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T
+      ge_precomp (Duif): (y+x,y-x,2dxy)
+    */
+    """)
+
+xmr_comments = textwrap.dedent("""\
+    /*
+     *
+     * xmr specific code
+     *
+     *
+    This code is from the original CryptoNote.
+    Some additional functions were needed to compute ring signatures
+    which are not needed for signing. 
+    Note that sc_sub and sc_mulsub have been given their own file
+    since these have been rewritten 
+
+    */
+    """)
+
+
+
+
+def qhasmToC(fi, header, out):
+    #replaces mentiones of "header" in "fi" with output in "out"
+    #also removes qhasm comments
+    out1 = out+".tmp"
+    rem_qhasm = " |grep -v 'qhasm' |grep -v ' asm'"
+    com = "sed -e '/#include \""+header+"\"/ {' -e 'r "+header+"' -e 'd' -e '}' "+fi+rem_qhasm+" > "+out1
+    com2 = "awk 'NF' "+out1+" > "+out
+    print(com)
+    os.system(com)
+    print(com2)
+    os.system(com2)
+    os.remove(out1) #temporary
+
+while (a != "m") and (a != "m") and (a != "c"):
+    a = raw_input("Make / Clean/ Quit    m / c / q?")
+
+if a == "m":
+    print("making crypto-ops.c and crypto-ops.h")
+
+
+    #ref10 header files
+
+    #ref10 c files
+
+    #fe things
+    #still need to do d2, d, sqrtm1
+    print("making fe.c")
+    print(fe_comments)
+    fe = glob.glob("fe*.c")
+    for g in fe:
+        os.system("cp "+g+" "+g.replace("fe", "fe.monero."))
+    qhasmToC("fe_pow22523.c", "pow22523.h", "fe.monero._pow22523.c")
+    qhasmToC("fe_invert.c", "pow225521.h", "fe.monero._invert.c")
+    os.system("rm fe.monero._isnonzero.c") #since it's modified, it's in xmrSpecificOld
+    os.system("cat fe.monero.*.c | grep -v '^#include' > fe.monero.c")
+
+    #sc things
+    print("\nmaking sc.c")
+    print(sc_comments)
+    #so you don't get multiple "loads"
+    os.system("tail -n +24 sc_reduce.c > sc.monero._reduce.c") #also good on linux
+    os.system("tail -n +24 sc_muladd.c > sc.monero._muladd.c")
+    os.system("tail -n +31 sc_sub.xmr.c > sc.monero._sub.xmr.c") #careful with the tails if you change these files!
+    os.system("cat sc.monero.*.c | grep -v '^#include' > sc.monero.c")
+
+    #ge stuff
+    print("making ge.c")
+    ge = glob.glob("ge*.c")
+    for g in ge:
+        os.system("cp "+g+" "+g.replace("ge", "ge.monero."))
+    print(ge_comments)
+    #need to substitute the below lines for their .h files in the appropriate places
+    qhasmToC("ge_add.c", "ge_add.h", "ge.monero._add.c")
+    qhasmToC("ge_madd.c", "ge_madd.h", "ge.monero._madd.c")
+    qhasmToC("ge_sub.c", "ge_sub.h", "ge.monero._sub.c")
+    qhasmToC("ge_msub.c", "ge_msub.h", "ge.monero._msub.c")
+    qhasmToC("ge_p2_dbl.c", "ge_p2_dbl.h", "ge.monero._p2_dbl.c")
+    qhasmToC("ge_frombytes.c", "d.h", "ge.monero._frombytes.c")
+    qhasmToC("ge.monero._frombytes.c", "sqrtm1.h", "ge.monero._frombytes.c")
+    qhasmToC("ge_p3_to_cached.c", "d2.h", "ge.monero._p3_to_cached.c")
+
+
+
+    #also ge_double_scalarmult needs base2.h for ge_precomp Bi
+    #note, base2.h is a large file!
+    #also in ge_scalarmult_base ge_precomp base needs base.h included
+
+    qhasmToC("ge_double_scalarmult.c", "base2.h", "ge.monero._double_scalarmult.c")
+    qhasmToC("ge_scalarmult_base.c", "base.h", "ge.monero._scalarmult_base.c")
+    #qhasmToC("ge.monero._scalarmult_base.c", "base.h", "ge.monero._scalarmult_base.c")
+    os.system("sed -i 's/ cmov/ ge_precomp_cmov/g' ge.monero._scalarmult_base.c")
+    os.system("cat ge.monero.*.c | grep -v '^#include' > ge.monero.c")
+
+
+    print("making crypto-ops.c")
+
+    #sqrtm1 things
+
+    #comments
+    with open("fe.monero.comments", "w") as text_file:
+            text_file.write(fe_comments)
+    with open("ge.monero.comments", "w") as text_file:
+            text_file.write(ge_comments)
+    with open("sc.monero.comments", "w") as text_file:
+            text_file.write(sc_comments)
+    with open("xmr.monero.comments", "w") as text_file:
+            text_file.write(xmr_comments)
+    with open("xmr.monero.predeclarations", "w") as text_file:
+            text_file.write(predeclarations)
+
+
+    #license
+    with open("monero.license", "w") as text_file:
+            text_file.write(license)
+
+    #crypto-ops.c includes
+    with open("crypto-ops.monero.includes", "w") as text_file:
+        text_file.write(crypto_ops_includes)
+
+    #note you may have duplicates of load_3, load_4 and possibly some other functions ... 
+    os.system("cat monero.license crypto-ops.monero.includes xmr.monero.predeclarations fe.monero.comments fe.monero.c sc.monero.comments sc.monero.c ge.monero.comments ge.monero.c xmr.monero.comments xmrSpecificOld.c > crypto-ops.c")
+
+    #monero specific header files
+    #print("making crypto-ops-tmp.h")
+    #os.system("cat fe.h ge.h sc.h |grep -v crypto_sign_ed25519 |grep -v fe.h > crypto-ops-tmp.h")
+    #we'll just use the old header crypto-ops.h
+
+    #replace crypto_ints
+    os.system("sed -i 's/crypto_int32/int32_t/g' crypto-ops.c")
+    os.system("sed -i 's/crypto_int64/int64_t/g' crypto-ops.c")
+    os.system("sed -i 's/crypto_uint32/uint32_t/g' crypto-ops.c")
+    os.system("sed -i 's/crypto_uint64/uint64_t/g' crypto-ops.c")
+
+    #cleaning up 
+    os.system("rm *monero*")
+
+    #monero specific c files
+if a == "c":
+    #turn the directory back into ref10
+    os.system("rm *monero*")
+    os.system("rm crypto-ops.c")
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/api.h b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/api.h
new file mode 100644
index 0000000000..d88dae0c32
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/api.h
@@ -0,0 +1,4 @@
+#define CRYPTO_SECRETKEYBYTES 64
+#define CRYPTO_PUBLICKEYBYTES 32
+#define CRYPTO_BYTES 64
+#define CRYPTO_DETERMINISTIC 1
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/base.h b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/base.h
new file mode 100644
index 0000000000..573bd8a05c
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/base.h
@@ -0,0 +1,1344 @@
+{
+ {
+  { 25967493,-14356035,29566456,3660896,-12694345,4014787,27544626,-11754271,-6079156,2047605 },
+  { -12545711,934262,-2722910,3049990,-727428,9406986,12720692,5043384,19500929,-15469378 },
+  { -8738181,4489570,9688441,-14785194,10184609,-12363380,29287919,11864899,-24514362,-4438546 },
+ },
+ {
+  { -12815894,-12976347,-21581243,11784320,-25355658,-2750717,-11717903,-3814571,-358445,-10211303 },
+  { -21703237,6903825,27185491,6451973,-29577724,-9554005,-15616551,11189268,-26829678,-5319081 },
+  { 26966642,11152617,32442495,15396054,14353839,-12752335,-3128826,-9541118,-15472047,-4166697 },
+ },
+ {
+  { 15636291,-9688557,24204773,-7912398,616977,-16685262,27787600,-14772189,28944400,-1550024 },
+  { 16568933,4717097,-11556148,-1102322,15682896,-11807043,16354577,-11775962,7689662,11199574 },
+  { 30464156,-5976125,-11779434,-15670865,23220365,15915852,7512774,10017326,-17749093,-9920357 },
+ },
+ {
+  { -17036878,13921892,10945806,-6033431,27105052,-16084379,-28926210,15006023,3284568,-6276540 },
+  { 23599295,-8306047,-11193664,-7687416,13236774,10506355,7464579,9656445,13059162,10374397 },
+  { 7798556,16710257,3033922,2874086,28997861,2835604,32406664,-3839045,-641708,-101325 },
+ },
+ {
+  { 10861363,11473154,27284546,1981175,-30064349,12577861,32867885,14515107,-15438304,10819380 },
+  { 4708026,6336745,20377586,9066809,-11272109,6594696,-25653668,12483688,-12668491,5581306 },
+  { 19563160,16186464,-29386857,4097519,10237984,-4348115,28542350,13850243,-23678021,-15815942 },
+ },
+ {
+  { -15371964,-12862754,32573250,4720197,-26436522,5875511,-19188627,-15224819,-9818940,-12085777 },
+  { -8549212,109983,15149363,2178705,22900618,4543417,3044240,-15689887,1762328,14866737 },
+  { -18199695,-15951423,-10473290,1707278,-17185920,3916101,-28236412,3959421,27914454,4383652 },
+ },
+ {
+  { 5153746,9909285,1723747,-2777874,30523605,5516873,19480852,5230134,-23952439,-15175766 },
+  { -30269007,-3463509,7665486,10083793,28475525,1649722,20654025,16520125,30598449,7715701 },
+  { 28881845,14381568,9657904,3680757,-20181635,7843316,-31400660,1370708,29794553,-1409300 },
+ },
+ {
+  { 14499471,-2729599,-33191113,-4254652,28494862,14271267,30290735,10876454,-33154098,2381726 },
+  { -7195431,-2655363,-14730155,462251,-27724326,3941372,-6236617,3696005,-32300832,15351955 },
+  { 27431194,8222322,16448760,-3907995,-18707002,11938355,-32961401,-2970515,29551813,10109425 },
+ },
+},
+{
+ {
+  { -13657040,-13155431,-31283750,11777098,21447386,6519384,-2378284,-1627556,10092783,-4764171 },
+  { 27939166,14210322,4677035,16277044,-22964462,-12398139,-32508754,12005538,-17810127,12803510 },
+  { 17228999,-15661624,-1233527,300140,-1224870,-11714777,30364213,-9038194,18016357,4397660 },
+ },
+ {
+  { -10958843,-7690207,4776341,-14954238,27850028,-15602212,-26619106,14544525,-17477504,982639 },
+  { 29253598,15796703,-2863982,-9908884,10057023,3163536,7332899,-4120128,-21047696,9934963 },
+  { 5793303,16271923,-24131614,-10116404,29188560,1206517,-14747930,4559895,-30123922,-10897950 },
+ },
+ {
+  { -27643952,-11493006,16282657,-11036493,28414021,-15012264,24191034,4541697,-13338309,5500568 },
+  { 12650548,-1497113,9052871,11355358,-17680037,-8400164,-17430592,12264343,10874051,13524335 },
+  { 25556948,-3045990,714651,2510400,23394682,-10415330,33119038,5080568,-22528059,5376628 },
+ },
+ {
+  { -26088264,-4011052,-17013699,-3537628,-6726793,1920897,-22321305,-9447443,4535768,1569007 },
+  { -2255422,14606630,-21692440,-8039818,28430649,8775819,-30494562,3044290,31848280,12543772 },
+  { -22028579,2943893,-31857513,6777306,13784462,-4292203,-27377195,-2062731,7718482,14474653 },
+ },
+ {
+  { 2385315,2454213,-22631320,46603,-4437935,-15680415,656965,-7236665,24316168,-5253567 },
+  { 13741529,10911568,-33233417,-8603737,-20177830,-1033297,33040651,-13424532,-20729456,8321686 },
+  { 21060490,-2212744,15712757,-4336099,1639040,10656336,23845965,-11874838,-9984458,608372 },
+ },
+ {
+  { -13672732,-15087586,-10889693,-7557059,-6036909,11305547,1123968,-6780577,27229399,23887 },
+  { -23244140,-294205,-11744728,14712571,-29465699,-2029617,12797024,-6440308,-1633405,16678954 },
+  { -29500620,4770662,-16054387,14001338,7830047,9564805,-1508144,-4795045,-17169265,4904953 },
+ },
+ {
+  { 24059557,14617003,19037157,-15039908,19766093,-14906429,5169211,16191880,2128236,-4326833 },
+  { -16981152,4124966,-8540610,-10653797,30336522,-14105247,-29806336,916033,-6882542,-2986532 },
+  { -22630907,12419372,-7134229,-7473371,-16478904,16739175,285431,2763829,15736322,4143876 },
+ },
+ {
+  { 2379352,11839345,-4110402,-5988665,11274298,794957,212801,-14594663,23527084,-16458268 },
+  { 33431127,-11130478,-17838966,-15626900,8909499,8376530,-32625340,4087881,-15188911,-14416214 },
+  { 1767683,7197987,-13205226,-2022635,-13091350,448826,5799055,4357868,-4774191,-16323038 },
+ },
+},
+{
+ {
+  { 6721966,13833823,-23523388,-1551314,26354293,-11863321,23365147,-3949732,7390890,2759800 },
+  { 4409041,2052381,23373853,10530217,7676779,-12885954,21302353,-4264057,1244380,-12919645 },
+  { -4421239,7169619,4982368,-2957590,30256825,-2777540,14086413,9208236,15886429,16489664 },
+ },
+ {
+  { 1996075,10375649,14346367,13311202,-6874135,-16438411,-13693198,398369,-30606455,-712933 },
+  { -25307465,9795880,-2777414,14878809,-33531835,14780363,13348553,12076947,-30836462,5113182 },
+  { -17770784,11797796,31950843,13929123,-25888302,12288344,-30341101,-7336386,13847711,5387222 },
+ },
+ {
+  { -18582163,-3416217,17824843,-2340966,22744343,-10442611,8763061,3617786,-19600662,10370991 },
+  { 20246567,-14369378,22358229,-543712,18507283,-10413996,14554437,-8746092,32232924,16763880 },
+  { 9648505,10094563,26416693,14745928,-30374318,-6472621,11094161,15689506,3140038,-16510092 },
+ },
+ {
+  { -16160072,5472695,31895588,4744994,8823515,10365685,-27224800,9448613,-28774454,366295 },
+  { 19153450,11523972,-11096490,-6503142,-24647631,5420647,28344573,8041113,719605,11671788 },
+  { 8678025,2694440,-6808014,2517372,4964326,11152271,-15432916,-15266516,27000813,-10195553 },
+ },
+ {
+  { -15157904,7134312,8639287,-2814877,-7235688,10421742,564065,5336097,6750977,-14521026 },
+  { 11836410,-3979488,26297894,16080799,23455045,15735944,1695823,-8819122,8169720,16220347 },
+  { -18115838,8653647,17578566,-6092619,-8025777,-16012763,-11144307,-2627664,-5990708,-14166033 },
+ },
+ {
+  { -23308498,-10968312,15213228,-10081214,-30853605,-11050004,27884329,2847284,2655861,1738395 },
+  { -27537433,-14253021,-25336301,-8002780,-9370762,8129821,21651608,-3239336,-19087449,-11005278 },
+  { 1533110,3437855,23735889,459276,29970501,11335377,26030092,5821408,10478196,8544890 },
+ },
+ {
+  { 32173121,-16129311,24896207,3921497,22579056,-3410854,19270449,12217473,17789017,-3395995 },
+  { -30552961,-2228401,-15578829,-10147201,13243889,517024,15479401,-3853233,30460520,1052596 },
+  { -11614875,13323618,32618793,8175907,-15230173,12596687,27491595,-4612359,3179268,-9478891 },
+ },
+ {
+  { 31947069,-14366651,-4640583,-15339921,-15125977,-6039709,-14756777,-16411740,19072640,-9511060 },
+  { 11685058,11822410,3158003,-13952594,33402194,-4165066,5977896,-5215017,473099,5040608 },
+  { -20290863,8198642,-27410132,11602123,1290375,-2799760,28326862,1721092,-19558642,-3131606 },
+ },
+},
+{
+ {
+  { 7881532,10687937,7578723,7738378,-18951012,-2553952,21820786,8076149,-27868496,11538389 },
+  { -19935666,3899861,18283497,-6801568,-15728660,-11249211,8754525,7446702,-5676054,5797016 },
+  { -11295600,-3793569,-15782110,-7964573,12708869,-8456199,2014099,-9050574,-2369172,-5877341 },
+ },
+ {
+  { -22472376,-11568741,-27682020,1146375,18956691,16640559,1192730,-3714199,15123619,10811505 },
+  { 14352098,-3419715,-18942044,10822655,32750596,4699007,-70363,15776356,-28886779,-11974553 },
+  { -28241164,-8072475,-4978962,-5315317,29416931,1847569,-20654173,-16484855,4714547,-9600655 },
+ },
+ {
+  { 15200332,8368572,19679101,15970074,-31872674,1959451,24611599,-4543832,-11745876,12340220 },
+  { 12876937,-10480056,33134381,6590940,-6307776,14872440,9613953,8241152,15370987,9608631 },
+  { -4143277,-12014408,8446281,-391603,4407738,13629032,-7724868,15866074,-28210621,-8814099 },
+ },
+ {
+  { 26660628,-15677655,8393734,358047,-7401291,992988,-23904233,858697,20571223,8420556 },
+  { 14620715,13067227,-15447274,8264467,14106269,15080814,33531827,12516406,-21574435,-12476749 },
+  { 236881,10476226,57258,-14677024,6472998,2466984,17258519,7256740,8791136,15069930 },
+ },
+ {
+  { 1276410,-9371918,22949635,-16322807,-23493039,-5702186,14711875,4874229,-30663140,-2331391 },
+  { 5855666,4990204,-13711848,7294284,-7804282,1924647,-1423175,-7912378,-33069337,9234253 },
+  { 20590503,-9018988,31529744,-7352666,-2706834,10650548,31559055,-11609587,18979186,13396066 },
+ },
+ {
+  { 24474287,4968103,22267082,4407354,24063882,-8325180,-18816887,13594782,33514650,7021958 },
+  { -11566906,-6565505,-21365085,15928892,-26158305,4315421,-25948728,-3916677,-21480480,12868082 },
+  { -28635013,13504661,19988037,-2132761,21078225,6443208,-21446107,2244500,-12455797,-8089383 },
+ },
+ {
+  { -30595528,13793479,-5852820,319136,-25723172,-6263899,33086546,8957937,-15233648,5540521 },
+  { -11630176,-11503902,-8119500,-7643073,2620056,1022908,-23710744,-1568984,-16128528,-14962807 },
+  { 23152971,775386,27395463,14006635,-9701118,4649512,1689819,892185,-11513277,-15205948 },
+ },
+ {
+  { 9770129,9586738,26496094,4324120,1556511,-3550024,27453819,4763127,-19179614,5867134 },
+  { -32765025,1927590,31726409,-4753295,23962434,-16019500,27846559,5931263,-29749703,-16108455 },
+  { 27461885,-2977536,22380810,1815854,-23033753,-3031938,7283490,-15148073,-19526700,7734629 },
+ },
+},
+{
+ {
+  { -8010264,-9590817,-11120403,6196038,29344158,-13430885,7585295,-3176626,18549497,15302069 },
+  { -32658337,-6171222,-7672793,-11051681,6258878,13504381,10458790,-6418461,-8872242,8424746 },
+  { 24687205,8613276,-30667046,-3233545,1863892,-1830544,19206234,7134917,-11284482,-828919 },
+ },
+ {
+  { 11334899,-9218022,8025293,12707519,17523892,-10476071,10243738,-14685461,-5066034,16498837 },
+  { 8911542,6887158,-9584260,-6958590,11145641,-9543680,17303925,-14124238,6536641,10543906 },
+  { -28946384,15479763,-17466835,568876,-1497683,11223454,-2669190,-16625574,-27235709,8876771 },
+ },
+ {
+  { -25742899,-12566864,-15649966,-846607,-33026686,-796288,-33481822,15824474,-604426,-9039817 },
+  { 10330056,70051,7957388,-9002667,9764902,15609756,27698697,-4890037,1657394,3084098 },
+  { 10477963,-7470260,12119566,-13250805,29016247,-5365589,31280319,14396151,-30233575,15272409 },
+ },
+ {
+  { -12288309,3169463,28813183,16658753,25116432,-5630466,-25173957,-12636138,-25014757,1950504 },
+  { -26180358,9489187,11053416,-14746161,-31053720,5825630,-8384306,-8767532,15341279,8373727 },
+  { 28685821,7759505,-14378516,-12002860,-31971820,4079242,298136,-10232602,-2878207,15190420 },
+ },
+ {
+  { -32932876,13806336,-14337485,-15794431,-24004620,10940928,8669718,2742393,-26033313,-6875003 },
+  { -1580388,-11729417,-25979658,-11445023,-17411874,-10912854,9291594,-16247779,-12154742,6048605 },
+  { -30305315,14843444,1539301,11864366,20201677,1900163,13934231,5128323,11213262,9168384 },
+ },
+ {
+  { -26280513,11007847,19408960,-940758,-18592965,-4328580,-5088060,-11105150,20470157,-16398701 },
+  { -23136053,9282192,14855179,-15390078,-7362815,-14408560,-22783952,14461608,14042978,5230683 },
+  { 29969567,-2741594,-16711867,-8552442,9175486,-2468974,21556951,3506042,-5933891,-12449708 },
+ },
+ {
+  { -3144746,8744661,19704003,4581278,-20430686,6830683,-21284170,8971513,-28539189,15326563 },
+  { -19464629,10110288,-17262528,-3503892,-23500387,1355669,-15523050,15300988,-20514118,9168260 },
+  { -5353335,4488613,-23803248,16314347,7780487,-15638939,-28948358,9601605,33087103,-9011387 },
+ },
+ {
+  { -19443170,-15512900,-20797467,-12445323,-29824447,10229461,-27444329,-15000531,-5996870,15664672 },
+  { 23294591,-16632613,-22650781,-8470978,27844204,11461195,13099750,-2460356,18151676,13417686 },
+  { -24722913,-4176517,-31150679,5988919,-26858785,6685065,1661597,-12551441,15271676,-15452665 },
+ },
+},
+{
+ {
+  { 11433042,-13228665,8239631,-5279517,-1985436,-725718,-18698764,2167544,-6921301,-13440182 },
+  { -31436171,15575146,30436815,12192228,-22463353,9395379,-9917708,-8638997,12215110,12028277 },
+  { 14098400,6555944,23007258,5757252,-15427832,-12950502,30123440,4617780,-16900089,-655628 },
+ },
+ {
+  { -4026201,-15240835,11893168,13718664,-14809462,1847385,-15819999,10154009,23973261,-12684474 },
+  { -26531820,-3695990,-1908898,2534301,-31870557,-16550355,18341390,-11419951,32013174,-10103539 },
+  { -25479301,10876443,-11771086,-14625140,-12369567,1838104,21911214,6354752,4425632,-837822 },
+ },
+ {
+  { -10433389,-14612966,22229858,-3091047,-13191166,776729,-17415375,-12020462,4725005,14044970 },
+  { 19268650,-7304421,1555349,8692754,-21474059,-9910664,6347390,-1411784,-19522291,-16109756 },
+  { -24864089,12986008,-10898878,-5558584,-11312371,-148526,19541418,8180106,9282262,10282508 },
+ },
+ {
+  { -26205082,4428547,-8661196,-13194263,4098402,-14165257,15522535,8372215,5542595,-10702683 },
+  { -10562541,14895633,26814552,-16673850,-17480754,-2489360,-2781891,6993761,-18093885,10114655 },
+  { -20107055,-929418,31422704,10427861,-7110749,6150669,-29091755,-11529146,25953725,-106158 },
+ },
+ {
+  { -4234397,-8039292,-9119125,3046000,2101609,-12607294,19390020,6094296,-3315279,12831125 },
+  { -15998678,7578152,5310217,14408357,-33548620,-224739,31575954,6326196,7381791,-2421839 },
+  { -20902779,3296811,24736065,-16328389,18374254,7318640,6295303,8082724,-15362489,12339664 },
+ },
+ {
+  { 27724736,2291157,6088201,-14184798,1792727,5857634,13848414,15768922,25091167,14856294 },
+  { -18866652,8331043,24373479,8541013,-701998,-9269457,12927300,-12695493,-22182473,-9012899 },
+  { -11423429,-5421590,11632845,3405020,30536730,-11674039,-27260765,13866390,30146206,9142070 },
+ },
+ {
+  { 3924129,-15307516,-13817122,-10054960,12291820,-668366,-27702774,9326384,-8237858,4171294 },
+  { -15921940,16037937,6713787,16606682,-21612135,2790944,26396185,3731949,345228,-5462949 },
+  { -21327538,13448259,25284571,1143661,20614966,-8849387,2031539,-12391231,-16253183,-13582083 },
+ },
+ {
+  { 31016211,-16722429,26371392,-14451233,-5027349,14854137,17477601,3842657,28012650,-16405420 },
+  { -5075835,9368966,-8562079,-4600902,-15249953,6970560,-9189873,16292057,-8867157,3507940 },
+  { 29439664,3537914,23333589,6997794,-17555561,-11018068,-15209202,-15051267,-9164929,6580396 },
+ },
+},
+{
+ {
+  { -12185861,-7679788,16438269,10826160,-8696817,-6235611,17860444,-9273846,-2095802,9304567 },
+  { 20714564,-4336911,29088195,7406487,11426967,-5095705,14792667,-14608617,5289421,-477127 },
+  { -16665533,-10650790,-6160345,-13305760,9192020,-1802462,17271490,12349094,26939669,-3752294 },
+ },
+ {
+  { -12889898,9373458,31595848,16374215,21471720,13221525,-27283495,-12348559,-3698806,117887 },
+  { 22263325,-6560050,3984570,-11174646,-15114008,-566785,28311253,5358056,-23319780,541964 },
+  { 16259219,3261970,2309254,-15534474,-16885711,-4581916,24134070,-16705829,-13337066,-13552195 },
+ },
+ {
+  { 9378160,-13140186,-22845982,-12745264,28198281,-7244098,-2399684,-717351,690426,14876244 },
+  { 24977353,-314384,-8223969,-13465086,28432343,-1176353,-13068804,-12297348,-22380984,6618999 },
+  { -1538174,11685646,12944378,13682314,-24389511,-14413193,8044829,-13817328,32239829,-5652762 },
+ },
+ {
+  { -18603066,4762990,-926250,8885304,-28412480,-3187315,9781647,-10350059,32779359,5095274 },
+  { -33008130,-5214506,-32264887,-3685216,9460461,-9327423,-24601656,14506724,21639561,-2630236 },
+  { -16400943,-13112215,25239338,15531969,3987758,-4499318,-1289502,-6863535,17874574,558605 },
+ },
+ {
+  { -13600129,10240081,9171883,16131053,-20869254,9599700,33499487,5080151,2085892,5119761 },
+  { -22205145,-2519528,-16381601,414691,-25019550,2170430,30634760,-8363614,-31999993,-5759884 },
+  { -6845704,15791202,8550074,-1312654,29928809,-12092256,27534430,-7192145,-22351378,12961482 },
+ },
+ {
+  { -24492060,-9570771,10368194,11582341,-23397293,-2245287,16533930,8206996,-30194652,-5159638 },
+  { -11121496,-3382234,2307366,6362031,-135455,8868177,-16835630,7031275,7589640,8945490 },
+  { -32152748,8917967,6661220,-11677616,-1192060,-15793393,7251489,-11182180,24099109,-14456170 },
+ },
+ {
+  { 5019558,-7907470,4244127,-14714356,-26933272,6453165,-19118182,-13289025,-6231896,-10280736 },
+  { 10853594,10721687,26480089,5861829,-22995819,1972175,-1866647,-10557898,-3363451,-6441124 },
+  { -17002408,5906790,221599,-6563147,7828208,-13248918,24362661,-2008168,-13866408,7421392 },
+ },
+ {
+  { 8139927,-6546497,32257646,-5890546,30375719,1886181,-21175108,15441252,28826358,-4123029 },
+  { 6267086,9695052,7709135,-16603597,-32869068,-1886135,14795160,-7840124,13746021,-1742048 },
+  { 28584902,7787108,-6732942,-15050729,22846041,-7571236,-3181936,-363524,4771362,-8419958 },
+ },
+},
+{
+ {
+  { 24949256,6376279,-27466481,-8174608,-18646154,-9930606,33543569,-12141695,3569627,11342593 },
+  { 26514989,4740088,27912651,3697550,19331575,-11472339,6809886,4608608,7325975,-14801071 },
+  { -11618399,-14554430,-24321212,7655128,-1369274,5214312,-27400540,10258390,-17646694,-8186692 },
+ },
+ {
+  { 11431204,15823007,26570245,14329124,18029990,4796082,-31446179,15580664,9280358,-3973687 },
+  { -160783,-10326257,-22855316,-4304997,-20861367,-13621002,-32810901,-11181622,-15545091,4387441 },
+  { -20799378,12194512,3937617,-5805892,-27154820,9340370,-24513992,8548137,20617071,-7482001 },
+ },
+ {
+  { -938825,-3930586,-8714311,16124718,24603125,-6225393,-13775352,-11875822,24345683,10325460 },
+  { -19855277,-1568885,-22202708,8714034,14007766,6928528,16318175,-1010689,4766743,3552007 },
+  { -21751364,-16730916,1351763,-803421,-4009670,3950935,3217514,14481909,10988822,-3994762 },
+ },
+ {
+  { 15564307,-14311570,3101243,5684148,30446780,-8051356,12677127,-6505343,-8295852,13296005 },
+  { -9442290,6624296,-30298964,-11913677,-4670981,-2057379,31521204,9614054,-30000824,12074674 },
+  { 4771191,-135239,14290749,-13089852,27992298,14998318,-1413936,-1556716,29832613,-16391035 },
+ },
+ {
+  { 7064884,-7541174,-19161962,-5067537,-18891269,-2912736,25825242,5293297,-27122660,13101590 },
+  { -2298563,2439670,-7466610,1719965,-27267541,-16328445,32512469,-5317593,-30356070,-4190957 },
+  { -30006540,10162316,-33180176,3981723,-16482138,-13070044,14413974,9515896,19568978,9628812 },
+ },
+ {
+  { 33053803,199357,15894591,1583059,27380243,-4580435,-17838894,-6106839,-6291786,3437740 },
+  { -18978877,3884493,19469877,12726490,15913552,13614290,-22961733,70104,7463304,4176122 },
+  { -27124001,10659917,11482427,-16070381,12771467,-6635117,-32719404,-5322751,24216882,5944158 },
+ },
+ {
+  { 8894125,7450974,-2664149,-9765752,-28080517,-12389115,19345746,14680796,11632993,5847885 },
+  { 26942781,-2315317,9129564,-4906607,26024105,11769399,-11518837,6367194,-9727230,4782140 },
+  { 19916461,-4828410,-22910704,-11414391,25606324,-5972441,33253853,8220911,6358847,-1873857 },
+ },
+ {
+  { 801428,-2081702,16569428,11065167,29875704,96627,7908388,-4480480,-13538503,1387155 },
+  { 19646058,5720633,-11416706,12814209,11607948,12749789,14147075,15156355,-21866831,11835260 },
+  { 19299512,1155910,28703737,14890794,2925026,7269399,26121523,15467869,-26560550,5052483 },
+ },
+},
+{
+ {
+  { -3017432,10058206,1980837,3964243,22160966,12322533,-6431123,-12618185,12228557,-7003677 },
+  { 32944382,14922211,-22844894,5188528,21913450,-8719943,4001465,13238564,-6114803,8653815 },
+  { 22865569,-4652735,27603668,-12545395,14348958,8234005,24808405,5719875,28483275,2841751 },
+ },
+ {
+  { -16420968,-1113305,-327719,-12107856,21886282,-15552774,-1887966,-315658,19932058,-12739203 },
+  { -11656086,10087521,-8864888,-5536143,-19278573,-3055912,3999228,13239134,-4777469,-13910208 },
+  { 1382174,-11694719,17266790,9194690,-13324356,9720081,20403944,11284705,-14013818,3093230 },
+ },
+ {
+  { 16650921,-11037932,-1064178,1570629,-8329746,7352753,-302424,16271225,-24049421,-6691850 },
+  { -21911077,-5927941,-4611316,-5560156,-31744103,-10785293,24123614,15193618,-21652117,-16739389 },
+  { -9935934,-4289447,-25279823,4372842,2087473,10399484,31870908,14690798,17361620,11864968 },
+ },
+ {
+  { -11307610,6210372,13206574,5806320,-29017692,-13967200,-12331205,-7486601,-25578460,-16240689 },
+  { 14668462,-12270235,26039039,15305210,25515617,4542480,10453892,6577524,9145645,-6443880 },
+  { 5974874,3053895,-9433049,-10385191,-31865124,3225009,-7972642,3936128,-5652273,-3050304 },
+ },
+ {
+  { 30625386,-4729400,-25555961,-12792866,-20484575,7695099,17097188,-16303496,-27999779,1803632 },
+  { -3553091,9865099,-5228566,4272701,-5673832,-16689700,14911344,12196514,-21405489,7047412 },
+  { 20093277,9920966,-11138194,-5343857,13161587,12044805,-32856851,4124601,-32343828,-10257566 },
+ },
+ {
+  { -20788824,14084654,-13531713,7842147,19119038,-13822605,4752377,-8714640,-21679658,2288038 },
+  { -26819236,-3283715,29965059,3039786,-14473765,2540457,29457502,14625692,-24819617,12570232 },
+  { -1063558,-11551823,16920318,12494842,1278292,-5869109,-21159943,-3498680,-11974704,4724943 },
+ },
+ {
+  { 17960970,-11775534,-4140968,-9702530,-8876562,-1410617,-12907383,-8659932,-29576300,1903856 },
+  { 23134274,-14279132,-10681997,-1611936,20684485,15770816,-12989750,3190296,26955097,14109738 },
+  { 15308788,5320727,-30113809,-14318877,22902008,7767164,29425325,-11277562,31960942,11934971 },
+ },
+ {
+  { -27395711,8435796,4109644,12222639,-24627868,14818669,20638173,4875028,10491392,1379718 },
+  { -13159415,9197841,3875503,-8936108,-1383712,-5879801,33518459,16176658,21432314,12180697 },
+  { -11787308,11500838,13787581,-13832590,-22430679,10140205,1465425,12689540,-10301319,-13872883 },
+ },
+},
+{
+ {
+  { 5414091,-15386041,-21007664,9643570,12834970,1186149,-2622916,-1342231,26128231,6032912 },
+  { -26337395,-13766162,32496025,-13653919,17847801,-12669156,3604025,8316894,-25875034,-10437358 },
+  { 3296484,6223048,24680646,-12246460,-23052020,5903205,-8862297,-4639164,12376617,3188849 },
+ },
+ {
+  { 29190488,-14659046,27549113,-1183516,3520066,-10697301,32049515,-7309113,-16109234,-9852307 },
+  { -14744486,-9309156,735818,-598978,-20407687,-5057904,25246078,-15795669,18640741,-960977 },
+  { -6928835,-16430795,10361374,5642961,4910474,12345252,-31638386,-494430,10530747,1053335 },
+ },
+ {
+  { -29265967,-14186805,-13538216,-12117373,-19457059,-10655384,-31462369,-2948985,24018831,15026644 },
+  { -22592535,-3145277,-2289276,5953843,-13440189,9425631,25310643,13003497,-2314791,-15145616 },
+  { -27419985,-603321,-8043984,-1669117,-26092265,13987819,-27297622,187899,-23166419,-2531735 },
+ },
+ {
+  { -21744398,-13810475,1844840,5021428,-10434399,-15911473,9716667,16266922,-5070217,726099 },
+  { 29370922,-6053998,7334071,-15342259,9385287,2247707,-13661962,-4839461,30007388,-15823341 },
+  { -936379,16086691,23751945,-543318,-1167538,-5189036,9137109,730663,9835848,4555336 },
+ },
+ {
+  { -23376435,1410446,-22253753,-12899614,30867635,15826977,17693930,544696,-11985298,12422646 },
+  { 31117226,-12215734,-13502838,6561947,-9876867,-12757670,-5118685,-4096706,29120153,13924425 },
+  { -17400879,-14233209,19675799,-2734756,-11006962,-5858820,-9383939,-11317700,7240931,-237388 },
+ },
+ {
+  { -31361739,-11346780,-15007447,-5856218,-22453340,-12152771,1222336,4389483,3293637,-15551743 },
+  { -16684801,-14444245,11038544,11054958,-13801175,-3338533,-24319580,7733547,12796905,-6335822 },
+  { -8759414,-10817836,-25418864,10783769,-30615557,-9746811,-28253339,3647836,3222231,-11160462 },
+ },
+ {
+  { 18606113,1693100,-25448386,-15170272,4112353,10045021,23603893,-2048234,-7550776,2484985 },
+  { 9255317,-3131197,-12156162,-1004256,13098013,-9214866,16377220,-2102812,-19802075,-3034702 },
+  { -22729289,7496160,-5742199,11329249,19991973,-3347502,-31718148,9936966,-30097688,-10618797 },
+ },
+ {
+  { 21878590,-5001297,4338336,13643897,-3036865,13160960,19708896,5415497,-7360503,-4109293 },
+  { 27736861,10103576,12500508,8502413,-3413016,-9633558,10436918,-1550276,-23659143,-8132100 },
+  { 19492550,-12104365,-29681976,-852630,-3208171,12403437,30066266,8367329,13243957,8709688 },
+ },
+},
+{
+ {
+  { 12015105,2801261,28198131,10151021,24818120,-4743133,-11194191,-5645734,5150968,7274186 },
+  { 2831366,-12492146,1478975,6122054,23825128,-12733586,31097299,6083058,31021603,-9793610 },
+  { -2529932,-2229646,445613,10720828,-13849527,-11505937,-23507731,16354465,15067285,-14147707 },
+ },
+ {
+  { 7840942,14037873,-33364863,15934016,-728213,-3642706,21403988,1057586,-19379462,-12403220 },
+  { 915865,-16469274,15608285,-8789130,-24357026,6060030,-17371319,8410997,-7220461,16527025 },
+  { 32922597,-556987,20336074,-16184568,10903705,-5384487,16957574,52992,23834301,6588044 },
+ },
+ {
+  { 32752030,11232950,3381995,-8714866,22652988,-10744103,17159699,16689107,-20314580,-1305992 },
+  { -4689649,9166776,-25710296,-10847306,11576752,12733943,7924251,-2752281,1976123,-7249027 },
+  { 21251222,16309901,-2983015,-6783122,30810597,12967303,156041,-3371252,12331345,-8237197 },
+ },
+ {
+  { 8651614,-4477032,-16085636,-4996994,13002507,2950805,29054427,-5106970,10008136,-4667901 },
+  { 31486080,15114593,-14261250,12951354,14369431,-7387845,16347321,-13662089,8684155,-10532952 },
+  { 19443825,11385320,24468943,-9659068,-23919258,2187569,-26263207,-6086921,31316348,14219878 },
+ },
+ {
+  { -28594490,1193785,32245219,11392485,31092169,15722801,27146014,6992409,29126555,9207390 },
+  { 32382935,1110093,18477781,11028262,-27411763,-7548111,-4980517,10843782,-7957600,-14435730 },
+  { 2814918,7836403,27519878,-7868156,-20894015,-11553689,-21494559,8550130,28346258,1994730 },
+ },
+ {
+  { -19578299,8085545,-14000519,-3948622,2785838,-16231307,-19516951,7174894,22628102,8115180 },
+  { -30405132,955511,-11133838,-15078069,-32447087,-13278079,-25651578,3317160,-9943017,930272 },
+  { -15303681,-6833769,28856490,1357446,23421993,1057177,24091212,-1388970,-22765376,-10650715 },
+ },
+ {
+  { -22751231,-5303997,-12907607,-12768866,-15811511,-7797053,-14839018,-16554220,-1867018,8398970 },
+  { -31969310,2106403,-4736360,1362501,12813763,16200670,22981545,-6291273,18009408,-15772772 },
+  { -17220923,-9545221,-27784654,14166835,29815394,7444469,29551787,-3727419,19288549,1325865 },
+ },
+ {
+  { 15100157,-15835752,-23923978,-1005098,-26450192,15509408,12376730,-3479146,33166107,-8042750 },
+  { 20909231,13023121,-9209752,16251778,-5778415,-8094914,12412151,10018715,2213263,-13878373 },
+  { 32529814,-11074689,30361439,-16689753,-9135940,1513226,22922121,6382134,-5766928,8371348 },
+ },
+},
+{
+ {
+  { 9923462,11271500,12616794,3544722,-29998368,-1721626,12891687,-8193132,-26442943,10486144 },
+  { -22597207,-7012665,8587003,-8257861,4084309,-12970062,361726,2610596,-23921530,-11455195 },
+  { 5408411,-1136691,-4969122,10561668,24145918,14240566,31319731,-4235541,19985175,-3436086 },
+ },
+ {
+  { -13994457,16616821,14549246,3341099,32155958,13648976,-17577068,8849297,65030,8370684 },
+  { -8320926,-12049626,31204563,5839400,-20627288,-1057277,-19442942,6922164,12743482,-9800518 },
+  { -2361371,12678785,28815050,4759974,-23893047,4884717,23783145,11038569,18800704,255233 },
+ },
+ {
+  { -5269658,-1773886,13957886,7990715,23132995,728773,13393847,9066957,19258688,-14753793 },
+  { -2936654,-10827535,-10432089,14516793,-3640786,4372541,-31934921,2209390,-1524053,2055794 },
+  { 580882,16705327,5468415,-2683018,-30926419,-14696000,-7203346,-8994389,-30021019,7394435 },
+ },
+ {
+  { 23838809,1822728,-15738443,15242727,8318092,-3733104,-21672180,-3492205,-4821741,14799921 },
+  { 13345610,9759151,3371034,-16137791,16353039,8577942,31129804,13496856,-9056018,7402518 },
+  { 2286874,-4435931,-20042458,-2008336,-13696227,5038122,11006906,-15760352,8205061,1607563 },
+ },
+ {
+  { 14414086,-8002132,3331830,-3208217,22249151,-5594188,18364661,-2906958,30019587,-9029278 },
+  { -27688051,1585953,-10775053,931069,-29120221,-11002319,-14410829,12029093,9944378,8024 },
+  { 4368715,-3709630,29874200,-15022983,-20230386,-11410704,-16114594,-999085,-8142388,5640030 },
+ },
+ {
+  { 10299610,13746483,11661824,16234854,7630238,5998374,9809887,-16694564,15219798,-14327783 },
+  { 27425505,-5719081,3055006,10660664,23458024,595578,-15398605,-1173195,-18342183,9742717 },
+  { 6744077,2427284,26042789,2720740,-847906,1118974,32324614,7406442,12420155,1994844 },
+ },
+ {
+  { 14012521,-5024720,-18384453,-9578469,-26485342,-3936439,-13033478,-10909803,24319929,-6446333 },
+  { 16412690,-4507367,10772641,15929391,-17068788,-4658621,10555945,-10484049,-30102368,-4739048 },
+  { 22397382,-7767684,-9293161,-12792868,17166287,-9755136,-27333065,6199366,21880021,-12250760 },
+ },
+ {
+  { -4283307,5368523,-31117018,8163389,-30323063,3209128,16557151,8890729,8840445,4957760 },
+  { -15447727,709327,-6919446,-10870178,-29777922,6522332,-21720181,12130072,-14796503,5005757 },
+  { -2114751,-14308128,23019042,15765735,-25269683,6002752,10183197,-13239326,-16395286,-2176112 },
+ },
+},
+{
+ {
+  { -19025756,1632005,13466291,-7995100,-23640451,16573537,-32013908,-3057104,22208662,2000468 },
+  { 3065073,-1412761,-25598674,-361432,-17683065,-5703415,-8164212,11248527,-3691214,-7414184 },
+  { 10379208,-6045554,8877319,1473647,-29291284,-12507580,16690915,2553332,-3132688,16400289 },
+ },
+ {
+  { 15716668,1254266,-18472690,7446274,-8448918,6344164,-22097271,-7285580,26894937,9132066 },
+  { 24158887,12938817,11085297,-8177598,-28063478,-4457083,-30576463,64452,-6817084,-2692882 },
+  { 13488534,7794716,22236231,5989356,25426474,-12578208,2350710,-3418511,-4688006,2364226 },
+ },
+ {
+  { 16335052,9132434,25640582,6678888,1725628,8517937,-11807024,-11697457,15445875,-7798101 },
+  { 29004207,-7867081,28661402,-640412,-12794003,-7943086,31863255,-4135540,-278050,-15759279 },
+  { -6122061,-14866665,-28614905,14569919,-10857999,-3591829,10343412,-6976290,-29828287,-10815811 },
+ },
+ {
+  { 27081650,3463984,14099042,-4517604,1616303,-6205604,29542636,15372179,17293797,960709 },
+  { 20263915,11434237,-5765435,11236810,13505955,-10857102,-16111345,6493122,-19384511,7639714 },
+  { -2830798,-14839232,25403038,-8215196,-8317012,-16173699,18006287,-16043750,29994677,-15808121 },
+ },
+ {
+  { 9769828,5202651,-24157398,-13631392,-28051003,-11561624,-24613141,-13860782,-31184575,709464 },
+  { 12286395,13076066,-21775189,-1176622,-25003198,4057652,-32018128,-8890874,16102007,13205847 },
+  { 13733362,5599946,10557076,3195751,-5557991,8536970,-25540170,8525972,10151379,10394400 },
+ },
+ {
+  { 4024660,-16137551,22436262,12276534,-9099015,-2686099,19698229,11743039,-33302334,8934414 },
+  { -15879800,-4525240,-8580747,-2934061,14634845,-698278,-9449077,3137094,-11536886,11721158 },
+  { 17555939,-5013938,8268606,2331751,-22738815,9761013,9319229,8835153,-9205489,-1280045 },
+ },
+ {
+  { -461409,-7830014,20614118,16688288,-7514766,-4807119,22300304,505429,6108462,-6183415 },
+  { -5070281,12367917,-30663534,3234473,32617080,-8422642,29880583,-13483331,-26898490,-7867459 },
+  { -31975283,5726539,26934134,10237677,-3173717,-605053,24199304,3795095,7592688,-14992079 },
+ },
+ {
+  { 21594432,-14964228,17466408,-4077222,32537084,2739898,6407723,12018833,-28256052,4298412 },
+  { -20650503,-11961496,-27236275,570498,3767144,-1717540,13891942,-1569194,13717174,10805743 },
+  { -14676630,-15644296,15287174,11927123,24177847,-8175568,-796431,14860609,-26938930,-5863836 },
+ },
+},
+{
+ {
+  { 12962541,5311799,-10060768,11658280,18855286,-7954201,13286263,-12808704,-4381056,9882022 },
+  { 18512079,11319350,-20123124,15090309,18818594,5271736,-22727904,3666879,-23967430,-3299429 },
+  { -6789020,-3146043,16192429,13241070,15898607,-14206114,-10084880,-6661110,-2403099,5276065 },
+ },
+ {
+  { 30169808,-5317648,26306206,-11750859,27814964,7069267,7152851,3684982,1449224,13082861 },
+  { 10342826,3098505,2119311,193222,25702612,12233820,23697382,15056736,-21016438,-8202000 },
+  { -33150110,3261608,22745853,7948688,19370557,-15177665,-26171976,6482814,-10300080,-11060101 },
+ },
+ {
+  { 32869458,-5408545,25609743,15678670,-10687769,-15471071,26112421,2521008,-22664288,6904815 },
+  { 29506923,4457497,3377935,-9796444,-30510046,12935080,1561737,3841096,-29003639,-6657642 },
+  { 10340844,-6630377,-18656632,-2278430,12621151,-13339055,30878497,-11824370,-25584551,5181966 },
+ },
+ {
+  { 25940115,-12658025,17324188,-10307374,-8671468,15029094,24396252,-16450922,-2322852,-12388574 },
+  { -21765684,9916823,-1300409,4079498,-1028346,11909559,1782390,12641087,20603771,-6561742 },
+  { -18882287,-11673380,24849422,11501709,13161720,-4768874,1925523,11914390,4662781,7820689 },
+ },
+ {
+  { 12241050,-425982,8132691,9393934,32846760,-1599620,29749456,12172924,16136752,15264020 },
+  { -10349955,-14680563,-8211979,2330220,-17662549,-14545780,10658213,6671822,19012087,3772772 },
+  { 3753511,-3421066,10617074,2028709,14841030,-6721664,28718732,-15762884,20527771,12988982 },
+ },
+ {
+  { -14822485,-5797269,-3707987,12689773,-898983,-10914866,-24183046,-10564943,3299665,-12424953 },
+  { -16777703,-15253301,-9642417,4978983,3308785,8755439,6943197,6461331,-25583147,8991218 },
+  { -17226263,1816362,-1673288,-6086439,31783888,-8175991,-32948145,7417950,-30242287,1507265 },
+ },
+ {
+  { 29692663,6829891,-10498800,4334896,20945975,-11906496,-28887608,8209391,14606362,-10647073 },
+  { -3481570,8707081,32188102,5672294,22096700,1711240,-33020695,9761487,4170404,-2085325 },
+  { -11587470,14855945,-4127778,-1531857,-26649089,15084046,22186522,16002000,-14276837,-8400798 },
+ },
+ {
+  { -4811456,13761029,-31703877,-2483919,-3312471,7869047,-7113572,-9620092,13240845,10965870 },
+  { -7742563,-8256762,-14768334,-13656260,-23232383,12387166,4498947,14147411,29514390,4302863 },
+  { -13413405,-12407859,20757302,-13801832,14785143,8976368,-5061276,-2144373,17846988,-13971927 },
+ },
+},
+{
+ {
+  { -2244452,-754728,-4597030,-1066309,-6247172,1455299,-21647728,-9214789,-5222701,12650267 },
+  { -9906797,-16070310,21134160,12198166,-27064575,708126,387813,13770293,-19134326,10958663 },
+  { 22470984,12369526,23446014,-5441109,-21520802,-9698723,-11772496,-11574455,-25083830,4271862 },
+ },
+ {
+  { -25169565,-10053642,-19909332,15361595,-5984358,2159192,75375,-4278529,-32526221,8469673 },
+  { 15854970,4148314,-8893890,7259002,11666551,13824734,-30531198,2697372,24154791,-9460943 },
+  { 15446137,-15806644,29759747,14019369,30811221,-9610191,-31582008,12840104,24913809,9815020 },
+ },
+ {
+  { -4709286,-5614269,-31841498,-12288893,-14443537,10799414,-9103676,13438769,18735128,9466238 },
+  { 11933045,9281483,5081055,-5183824,-2628162,-4905629,-7727821,-10896103,-22728655,16199064 },
+  { 14576810,379472,-26786533,-8317236,-29426508,-10812974,-102766,1876699,30801119,2164795 },
+ },
+ {
+  { 15995086,3199873,13672555,13712240,-19378835,-4647646,-13081610,-15496269,-13492807,1268052 },
+  { -10290614,-3659039,-3286592,10948818,23037027,3794475,-3470338,-12600221,-17055369,3565904 },
+  { 29210088,-9419337,-5919792,-4952785,10834811,-13327726,-16512102,-10820713,-27162222,-14030531 },
+ },
+ {
+  { -13161890,15508588,16663704,-8156150,-28349942,9019123,-29183421,-3769423,2244111,-14001979 },
+  { -5152875,-3800936,-9306475,-6071583,16243069,14684434,-25673088,-16180800,13491506,4641841 },
+  { 10813417,643330,-19188515,-728916,30292062,-16600078,27548447,-7721242,14476989,-12767431 },
+ },
+ {
+  { 10292079,9984945,6481436,8279905,-7251514,7032743,27282937,-1644259,-27912810,12651324 },
+  { -31185513,-813383,22271204,11835308,10201545,15351028,17099662,3988035,21721536,-3148940 },
+  { 10202177,-6545839,-31373232,-9574638,-32150642,-8119683,-12906320,3852694,13216206,14842320 },
+ },
+ {
+  { -15815640,-10601066,-6538952,-7258995,-6984659,-6581778,-31500847,13765824,-27434397,9900184 },
+  { 14465505,-13833331,-32133984,-14738873,-27443187,12990492,33046193,15796406,-7051866,-8040114 },
+  { 30924417,-8279620,6359016,-12816335,16508377,9071735,-25488601,15413635,9524356,-7018878 },
+ },
+ {
+  { 12274201,-13175547,32627641,-1785326,6736625,13267305,5237659,-5109483,15663516,4035784 },
+  { -2951309,8903985,17349946,601635,-16432815,-4612556,-13732739,-15889334,-22258478,4659091 },
+  { -16916263,-4952973,-30393711,-15158821,20774812,15897498,5736189,15026997,-2178256,-13455585 },
+ },
+},
+{
+ {
+  { -8858980,-2219056,28571666,-10155518,-474467,-10105698,-3801496,278095,23440562,-290208 },
+  { 10226241,-5928702,15139956,120818,-14867693,5218603,32937275,11551483,-16571960,-7442864 },
+  { 17932739,-12437276,-24039557,10749060,11316803,7535897,22503767,5561594,-3646624,3898661 },
+ },
+ {
+  { 7749907,-969567,-16339731,-16464,-25018111,15122143,-1573531,7152530,21831162,1245233 },
+  { 26958459,-14658026,4314586,8346991,-5677764,11960072,-32589295,-620035,-30402091,-16716212 },
+  { -12165896,9166947,33491384,13673479,29787085,13096535,6280834,14587357,-22338025,13987525 },
+ },
+ {
+  { -24349909,7778775,21116000,15572597,-4833266,-5357778,-4300898,-5124639,-7469781,-2858068 },
+  { 9681908,-6737123,-31951644,13591838,-6883821,386950,31622781,6439245,-14581012,4091397 },
+  { -8426427,1470727,-28109679,-1596990,3978627,-5123623,-19622683,12092163,29077877,-14741988 },
+ },
+ {
+  { 5269168,-6859726,-13230211,-8020715,25932563,1763552,-5606110,-5505881,-20017847,2357889 },
+  { 32264008,-15407652,-5387735,-1160093,-2091322,-3946900,23104804,-12869908,5727338,189038 },
+  { 14609123,-8954470,-6000566,-16622781,-14577387,-7743898,-26745169,10942115,-25888931,-14884697 },
+ },
+ {
+  { 20513500,5557931,-15604613,7829531,26413943,-2019404,-21378968,7471781,13913677,-5137875 },
+  { -25574376,11967826,29233242,12948236,-6754465,4713227,-8940970,14059180,12878652,8511905 },
+  { -25656801,3393631,-2955415,-7075526,-2250709,9366908,-30223418,6812974,5568676,-3127656 },
+ },
+ {
+  { 11630004,12144454,2116339,13606037,27378885,15676917,-17408753,-13504373,-14395196,8070818 },
+  { 27117696,-10007378,-31282771,-5570088,1127282,12772488,-29845906,10483306,-11552749,-1028714 },
+  { 10637467,-5688064,5674781,1072708,-26343588,-6982302,-1683975,9177853,-27493162,15431203 },
+ },
+ {
+  { 20525145,10892566,-12742472,12779443,-29493034,16150075,-28240519,14943142,-15056790,-7935931 },
+  { -30024462,5626926,-551567,-9981087,753598,11981191,25244767,-3239766,-3356550,9594024 },
+  { -23752644,2636870,-5163910,-10103818,585134,7877383,11345683,-6492290,13352335,-10977084 },
+ },
+ {
+  { -1931799,-5407458,3304649,-12884869,17015806,-4877091,-29783850,-7752482,-13215537,-319204 },
+  { 20239939,6607058,6203985,3483793,-18386976,-779229,-20723742,15077870,-22750759,14523817 },
+  { 27406042,-6041657,27423596,-4497394,4996214,10002360,-28842031,-4545494,-30172742,-4805667 },
+ },
+},
+{
+ {
+  { 11374242,12660715,17861383,-12540833,10935568,1099227,-13886076,-9091740,-27727044,11358504 },
+  { -12730809,10311867,1510375,10778093,-2119455,-9145702,32676003,11149336,-26123651,4985768 },
+  { -19096303,341147,-6197485,-239033,15756973,-8796662,-983043,13794114,-19414307,-15621255 },
+ },
+ {
+  { 6490081,11940286,25495923,-7726360,8668373,-8751316,3367603,6970005,-1691065,-9004790 },
+  { 1656497,13457317,15370807,6364910,13605745,8362338,-19174622,-5475723,-16796596,-5031438 },
+  { -22273315,-13524424,-64685,-4334223,-18605636,-10921968,-20571065,-7007978,-99853,-10237333 },
+ },
+ {
+  { 17747465,10039260,19368299,-4050591,-20630635,-16041286,31992683,-15857976,-29260363,-5511971 },
+  { 31932027,-4986141,-19612382,16366580,22023614,88450,11371999,-3744247,4882242,-10626905 },
+  { 29796507,37186,19818052,10115756,-11829032,3352736,18551198,3272828,-5190932,-4162409 },
+ },
+ {
+  { 12501286,4044383,-8612957,-13392385,-32430052,5136599,-19230378,-3529697,330070,-3659409 },
+  { 6384877,2899513,17807477,7663917,-2358888,12363165,25366522,-8573892,-271295,12071499 },
+  { -8365515,-4042521,25133448,-4517355,-6211027,2265927,-32769618,1936675,-5159697,3829363 },
+ },
+ {
+  { 28425966,-5835433,-577090,-4697198,-14217555,6870930,7921550,-6567787,26333140,14267664 },
+  { -11067219,11871231,27385719,-10559544,-4585914,-11189312,10004786,-8709488,-21761224,8930324 },
+  { -21197785,-16396035,25654216,-1725397,12282012,11008919,1541940,4757911,-26491501,-16408940 },
+ },
+ {
+  { 13537262,-7759490,-20604840,10961927,-5922820,-13218065,-13156584,6217254,-15943699,13814990 },
+  { -17422573,15157790,18705543,29619,24409717,-260476,27361681,9257833,-1956526,-1776914 },
+  { -25045300,-10191966,15366585,15166509,-13105086,8423556,-29171540,12361135,-18685978,4578290 },
+ },
+ {
+  { 24579768,3711570,1342322,-11180126,-27005135,14124956,-22544529,14074919,21964432,8235257 },
+  { -6528613,-2411497,9442966,-5925588,12025640,-1487420,-2981514,-1669206,13006806,2355433 },
+  { -16304899,-13605259,-6632427,-5142349,16974359,-10911083,27202044,1719366,1141648,-12796236 },
+ },
+ {
+  { -12863944,-13219986,-8318266,-11018091,-6810145,-4843894,13475066,-3133972,32674895,13715045 },
+  { 11423335,-5468059,32344216,8962751,24989809,9241752,-13265253,16086212,-28740881,-15642093 },
+  { -1409668,12530728,-6368726,10847387,19531186,-14132160,-11709148,7791794,-27245943,4383347 },
+ },
+},
+{
+ {
+  { -28970898,5271447,-1266009,-9736989,-12455236,16732599,-4862407,-4906449,27193557,6245191 },
+  { -15193956,5362278,-1783893,2695834,4960227,12840725,23061898,3260492,22510453,8577507 },
+  { -12632451,11257346,-32692994,13548177,-721004,10879011,31168030,13952092,-29571492,-3635906 },
+ },
+ {
+  { 3877321,-9572739,32416692,5405324,-11004407,-13656635,3759769,11935320,5611860,8164018 },
+  { -16275802,14667797,15906460,12155291,-22111149,-9039718,32003002,-8832289,5773085,-8422109 },
+  { -23788118,-8254300,1950875,8937633,18686727,16459170,-905725,12376320,31632953,190926 },
+ },
+ {
+  { -24593607,-16138885,-8423991,13378746,14162407,6901328,-8288749,4508564,-25341555,-3627528 },
+  { 8884438,-5884009,6023974,10104341,-6881569,-4941533,18722941,-14786005,-1672488,827625 },
+  { -32720583,-16289296,-32503547,7101210,13354605,2659080,-1800575,-14108036,-24878478,1541286 },
+ },
+ {
+  { 2901347,-1117687,3880376,-10059388,-17620940,-3612781,-21802117,-3567481,20456845,-1885033 },
+  { 27019610,12299467,-13658288,-1603234,-12861660,-4861471,-19540150,-5016058,29439641,15138866 },
+  { 21536104,-6626420,-32447818,-10690208,-22408077,5175814,-5420040,-16361163,7779328,109896 },
+ },
+ {
+  { 30279744,14648750,-8044871,6425558,13639621,-743509,28698390,12180118,23177719,-554075 },
+  { 26572847,3405927,-31701700,12890905,-19265668,5335866,-6493768,2378492,4439158,-13279347 },
+  { -22716706,3489070,-9225266,-332753,18875722,-1140095,14819434,-12731527,-17717757,-5461437 },
+ },
+ {
+  { -5056483,16566551,15953661,3767752,-10436499,15627060,-820954,2177225,8550082,-15114165 },
+  { -18473302,16596775,-381660,15663611,22860960,15585581,-27844109,-3582739,-23260460,-8428588 },
+  { -32480551,15707275,-8205912,-5652081,29464558,2713815,-22725137,15860482,-21902570,1494193 },
+ },
+ {
+  { -19562091,-14087393,-25583872,-9299552,13127842,759709,21923482,16529112,8742704,12967017 },
+  { -28464899,1553205,32536856,-10473729,-24691605,-406174,-8914625,-2933896,-29903758,15553883 },
+  { 21877909,3230008,9881174,10539357,-4797115,2841332,11543572,14513274,19375923,-12647961 },
+ },
+ {
+  { 8832269,-14495485,13253511,5137575,5037871,4078777,24880818,-6222716,2862653,9455043 },
+  { 29306751,5123106,20245049,-14149889,9592566,8447059,-2077124,-2990080,15511449,4789663 },
+  { -20679756,7004547,8824831,-9434977,-4045704,-3750736,-5754762,108893,23513200,16652362 },
+ },
+},
+{
+ {
+  { -33256173,4144782,-4476029,-6579123,10770039,-7155542,-6650416,-12936300,-18319198,10212860 },
+  { 2756081,8598110,7383731,-6859892,22312759,-1105012,21179801,2600940,-9988298,-12506466 },
+  { -24645692,13317462,-30449259,-15653928,21365574,-10869657,11344424,864440,-2499677,-16710063 },
+ },
+ {
+  { -26432803,6148329,-17184412,-14474154,18782929,-275997,-22561534,211300,2719757,4940997 },
+  { -1323882,3911313,-6948744,14759765,-30027150,7851207,21690126,8518463,26699843,5276295 },
+  { -13149873,-6429067,9396249,365013,24703301,-10488939,1321586,149635,-15452774,7159369 },
+ },
+ {
+  { 9987780,-3404759,17507962,9505530,9731535,-2165514,22356009,8312176,22477218,-8403385 },
+  { 18155857,-16504990,19744716,9006923,15154154,-10538976,24256460,-4864995,-22548173,9334109 },
+  { 2986088,-4911893,10776628,-3473844,10620590,-7083203,-21413845,14253545,-22587149,536906 },
+ },
+ {
+  { 4377756,8115836,24567078,15495314,11625074,13064599,7390551,10589625,10838060,-15420424 },
+  { -19342404,867880,9277171,-3218459,-14431572,-1986443,19295826,-15796950,6378260,699185 },
+  { 7895026,4057113,-7081772,-13077756,-17886831,-323126,-716039,15693155,-5045064,-13373962 },
+ },
+ {
+  { -7737563,-5869402,-14566319,-7406919,11385654,13201616,31730678,-10962840,-3918636,-9669325 },
+  { 10188286,-15770834,-7336361,13427543,22223443,14896287,30743455,7116568,-21786507,5427593 },
+  { 696102,13206899,27047647,-10632082,15285305,-9853179,10798490,-4578720,19236243,12477404 },
+ },
+ {
+  { -11229439,11243796,-17054270,-8040865,-788228,-8167967,-3897669,11180504,-23169516,7733644 },
+  { 17800790,-14036179,-27000429,-11766671,23887827,3149671,23466177,-10538171,10322027,15313801 },
+  { 26246234,11968874,32263343,-5468728,6830755,-13323031,-15794704,-101982,-24449242,10890804 },
+ },
+ {
+  { -31365647,10271363,-12660625,-6267268,16690207,-13062544,-14982212,16484931,25180797,-5334884 },
+  { -586574,10376444,-32586414,-11286356,19801893,10997610,2276632,9482883,316878,13820577 },
+  { -9882808,-4510367,-2115506,16457136,-11100081,11674996,30756178,-7515054,30696930,-3712849 },
+ },
+ {
+  { 32988917,-9603412,12499366,7910787,-10617257,-11931514,-7342816,-9985397,-32349517,7392473 },
+  { -8855661,15927861,9866406,-3649411,-2396914,-16655781,-30409476,-9134995,25112947,-2926644 },
+  { -2504044,-436966,25621774,-5678772,15085042,-5479877,-24884878,-13526194,5537438,-13914319 },
+ },
+},
+{
+ {
+  { -11225584,2320285,-9584280,10149187,-33444663,5808648,-14876251,-1729667,31234590,6090599 },
+  { -9633316,116426,26083934,2897444,-6364437,-2688086,609721,15878753,-6970405,-9034768 },
+  { -27757857,247744,-15194774,-9002551,23288161,-10011936,-23869595,6503646,20650474,1804084 },
+ },
+ {
+  { -27589786,15456424,8972517,8469608,15640622,4439847,3121995,-10329713,27842616,-202328 },
+  { -15306973,2839644,22530074,10026331,4602058,5048462,28248656,5031932,-11375082,12714369 },
+  { 20807691,-7270825,29286141,11421711,-27876523,-13868230,-21227475,1035546,-19733229,12796920 },
+ },
+ {
+  { 12076899,-14301286,-8785001,-11848922,-25012791,16400684,-17591495,-12899438,3480665,-15182815 },
+  { -32361549,5457597,28548107,7833186,7303070,-11953545,-24363064,-15921875,-33374054,2771025 },
+  { -21389266,421932,26597266,6860826,22486084,-6737172,-17137485,-4210226,-24552282,15673397 },
+ },
+ {
+  { -20184622,2338216,19788685,-9620956,-4001265,-8740893,-20271184,4733254,3727144,-12934448 },
+  { 6120119,814863,-11794402,-622716,6812205,-15747771,2019594,7975683,31123697,-10958981 },
+  { 30069250,-11435332,30434654,2958439,18399564,-976289,12296869,9204260,-16432438,9648165 },
+ },
+ {
+  { 32705432,-1550977,30705658,7451065,-11805606,9631813,3305266,5248604,-26008332,-11377501 },
+  { 17219865,2375039,-31570947,-5575615,-19459679,9219903,294711,15298639,2662509,-16297073 },
+  { -1172927,-7558695,-4366770,-4287744,-21346413,-8434326,32087529,-1222777,32247248,-14389861 },
+ },
+ {
+  { 14312628,1221556,17395390,-8700143,-4945741,-8684635,-28197744,-9637817,-16027623,-13378845 },
+  { -1428825,-9678990,-9235681,6549687,-7383069,-468664,23046502,9803137,17597934,2346211 },
+  { 18510800,15337574,26171504,981392,-22241552,7827556,-23491134,-11323352,3059833,-11782870 },
+ },
+ {
+  { 10141598,6082907,17829293,-1947643,9830092,13613136,-25556636,-5544586,-33502212,3592096 },
+  { 33114168,-15889352,-26525686,-13343397,33076705,8716171,1151462,1521897,-982665,-6837803 },
+  { -32939165,-4255815,23947181,-324178,-33072974,-12305637,-16637686,3891704,26353178,693168 },
+ },
+ {
+  { 30374239,1595580,-16884039,13186931,4600344,406904,9585294,-400668,31375464,14369965 },
+  { -14370654,-7772529,1510301,6434173,-18784789,-6262728,32732230,-13108839,17901441,16011505 },
+  { 18171223,-11934626,-12500402,15197122,-11038147,-15230035,-19172240,-16046376,8764035,12309598 },
+ },
+},
+{
+ {
+  { 5975908,-5243188,-19459362,-9681747,-11541277,14015782,-23665757,1228319,17544096,-10593782 },
+  { 5811932,-1715293,3442887,-2269310,-18367348,-8359541,-18044043,-15410127,-5565381,12348900 },
+  { -31399660,11407555,25755363,6891399,-3256938,14872274,-24849353,8141295,-10632534,-585479 },
+ },
+ {
+  { -12675304,694026,-5076145,13300344,14015258,-14451394,-9698672,-11329050,30944593,1130208 },
+  { 8247766,-6710942,-26562381,-7709309,-14401939,-14648910,4652152,2488540,23550156,-271232 },
+  { 17294316,-3788438,7026748,15626851,22990044,113481,2267737,-5908146,-408818,-137719 },
+ },
+ {
+  { 16091085,-16253926,18599252,7340678,2137637,-1221657,-3364161,14550936,3260525,-7166271 },
+  { -4910104,-13332887,18550887,10864893,-16459325,-7291596,-23028869,-13204905,-12748722,2701326 },
+  { -8574695,16099415,4629974,-16340524,-20786213,-6005432,-10018363,9276971,11329923,1862132 },
+ },
+ {
+  { 14763076,-15903608,-30918270,3689867,3511892,10313526,-21951088,12219231,-9037963,-940300 },
+  { 8894987,-3446094,6150753,3013931,301220,15693451,-31981216,-2909717,-15438168,11595570 },
+  { 15214962,3537601,-26238722,-14058872,4418657,-15230761,13947276,10730794,-13489462,-4363670 },
+ },
+ {
+  { -2538306,7682793,32759013,263109,-29984731,-7955452,-22332124,-10188635,977108,699994 },
+  { -12466472,4195084,-9211532,550904,-15565337,12917920,19118110,-439841,-30534533,-14337913 },
+  { 31788461,-14507657,4799989,7372237,8808585,-14747943,9408237,-10051775,12493932,-5409317 },
+ },
+ {
+  { -25680606,5260744,-19235809,-6284470,-3695942,16566087,27218280,2607121,29375955,6024730 },
+  { 842132,-2794693,-4763381,-8722815,26332018,-12405641,11831880,6985184,-9940361,2854096 },
+  { -4847262,-7969331,2516242,-5847713,9695691,-7221186,16512645,960770,12121869,16648078 },
+ },
+ {
+  { -15218652,14667096,-13336229,2013717,30598287,-464137,-31504922,-7882064,20237806,2838411 },
+  { -19288047,4453152,15298546,-16178388,22115043,-15972604,12544294,-13470457,1068881,-12499905 },
+  { -9558883,-16518835,33238498,13506958,30505848,-1114596,-8486907,-2630053,12521378,4845654 },
+ },
+ {
+  { -28198521,10744108,-2958380,10199664,7759311,-13088600,3409348,-873400,-6482306,-12885870 },
+  { -23561822,6230156,-20382013,10655314,-24040585,-11621172,10477734,-1240216,-3113227,13974498 },
+  { 12966261,15550616,-32038948,-1615346,21025980,-629444,5642325,7188737,18895762,12629579 },
+ },
+},
+{
+ {
+  { 14741879,-14946887,22177208,-11721237,1279741,8058600,11758140,789443,32195181,3895677 },
+  { 10758205,15755439,-4509950,9243698,-4879422,6879879,-2204575,-3566119,-8982069,4429647 },
+  { -2453894,15725973,-20436342,-10410672,-5803908,-11040220,-7135870,-11642895,18047436,-15281743 },
+ },
+ {
+  { -25173001,-11307165,29759956,11776784,-22262383,-15820455,10993114,-12850837,-17620701,-9408468 },
+  { 21987233,700364,-24505048,14972008,-7774265,-5718395,32155026,2581431,-29958985,8773375 },
+  { -25568350,454463,-13211935,16126715,25240068,8594567,20656846,12017935,-7874389,-13920155 },
+ },
+ {
+  { 6028182,6263078,-31011806,-11301710,-818919,2461772,-31841174,-5468042,-1721788,-2776725 },
+  { -12278994,16624277,987579,-5922598,32908203,1248608,7719845,-4166698,28408820,6816612 },
+  { -10358094,-8237829,19549651,-12169222,22082623,16147817,20613181,13982702,-10339570,5067943 },
+ },
+ {
+  { -30505967,-3821767,12074681,13582412,-19877972,2443951,-19719286,12746132,5331210,-10105944 },
+  { 30528811,3601899,-1957090,4619785,-27361822,-15436388,24180793,-12570394,27679908,-1648928 },
+  { 9402404,-13957065,32834043,10838634,-26580150,-13237195,26653274,-8685565,22611444,-12715406 },
+ },
+ {
+  { 22190590,1118029,22736441,15130463,-30460692,-5991321,19189625,-4648942,4854859,6622139 },
+  { -8310738,-2953450,-8262579,-3388049,-10401731,-271929,13424426,-3567227,26404409,13001963 },
+  { -31241838,-15415700,-2994250,8939346,11562230,-12840670,-26064365,-11621720,-15405155,11020693 },
+ },
+ {
+  { 1866042,-7949489,-7898649,-10301010,12483315,13477547,3175636,-12424163,28761762,1406734 },
+  { -448555,-1777666,13018551,3194501,-9580420,-11161737,24760585,-4347088,25577411,-13378680 },
+  { -24290378,4759345,-690653,-1852816,2066747,10693769,-29595790,9884936,-9368926,4745410 },
+ },
+ {
+  { -9141284,6049714,-19531061,-4341411,-31260798,9944276,-15462008,-11311852,10931924,-11931931 },
+  { -16561513,14112680,-8012645,4817318,-8040464,-11414606,-22853429,10856641,-20470770,13434654 },
+  { 22759489,-10073434,-16766264,-1871422,13637442,-10168091,1765144,-12654326,28445307,-5364710 },
+ },
+ {
+  { 29875063,12493613,2795536,-3786330,1710620,15181182,-10195717,-8788675,9074234,1167180 },
+  { -26205683,11014233,-9842651,-2635485,-26908120,7532294,-18716888,-9535498,3843903,9367684 },
+  { -10969595,-6403711,9591134,9582310,11349256,108879,16235123,8601684,-139197,4242895 },
+ },
+},
+{
+ {
+  { 22092954,-13191123,-2042793,-11968512,32186753,-11517388,-6574341,2470660,-27417366,16625501 },
+  { -11057722,3042016,13770083,-9257922,584236,-544855,-7770857,2602725,-27351616,14247413 },
+  { 6314175,-10264892,-32772502,15957557,-10157730,168750,-8618807,14290061,27108877,-1180880 },
+ },
+ {
+  { -8586597,-7170966,13241782,10960156,-32991015,-13794596,33547976,-11058889,-27148451,981874 },
+  { 22833440,9293594,-32649448,-13618667,-9136966,14756819,-22928859,-13970780,-10479804,-16197962 },
+  { -7768587,3326786,-28111797,10783824,19178761,14905060,22680049,13906969,-15933690,3797899 },
+ },
+ {
+  { 21721356,-4212746,-12206123,9310182,-3882239,-13653110,23740224,-2709232,20491983,-8042152 },
+  { 9209270,-15135055,-13256557,-6167798,-731016,15289673,25947805,15286587,30997318,-6703063 },
+  { 7392032,16618386,23946583,-8039892,-13265164,-1533858,-14197445,-2321576,17649998,-250080 },
+ },
+ {
+  { -9301088,-14193827,30609526,-3049543,-25175069,-1283752,-15241566,-9525724,-2233253,7662146 },
+  { -17558673,1763594,-33114336,15908610,-30040870,-12174295,7335080,-8472199,-3174674,3440183 },
+  { -19889700,-5977008,-24111293,-9688870,10799743,-16571957,40450,-4431835,4862400,1133 },
+ },
+ {
+  { -32856209,-7873957,-5422389,14860950,-16319031,7956142,7258061,311861,-30594991,-7379421 },
+  { -3773428,-1565936,28985340,7499440,24445838,9325937,29727763,16527196,18278453,15405622 },
+  { -4381906,8508652,-19898366,-3674424,-5984453,15149970,-13313598,843523,-21875062,13626197 },
+ },
+ {
+  { 2281448,-13487055,-10915418,-2609910,1879358,16164207,-10783882,3953792,13340839,15928663 },
+  { 31727126,-7179855,-18437503,-8283652,2875793,-16390330,-25269894,-7014826,-23452306,5964753 },
+  { 4100420,-5959452,-17179337,6017714,-18705837,12227141,-26684835,11344144,2538215,-7570755 },
+ },
+ {
+  { -9433605,6123113,11159803,-2156608,30016280,14966241,-20474983,1485421,-629256,-15958862 },
+  { -26804558,4260919,11851389,9658551,-32017107,16367492,-20205425,-13191288,11659922,-11115118 },
+  { 26180396,10015009,-30844224,-8581293,5418197,9480663,2231568,-10170080,33100372,-1306171 },
+ },
+ {
+  { 15121113,-5201871,-10389905,15427821,-27509937,-15992507,21670947,4486675,-5931810,-14466380 },
+  { 16166486,-9483733,-11104130,6023908,-31926798,-1364923,2340060,-16254968,-10735770,-10039824 },
+  { 28042865,-3557089,-12126526,12259706,-3717498,-6945899,6766453,-8689599,18036436,5803270 },
+ },
+},
+{
+ {
+  { -817581,6763912,11803561,1585585,10958447,-2671165,23855391,4598332,-6159431,-14117438 },
+  { -31031306,-14256194,17332029,-2383520,31312682,-5967183,696309,50292,-20095739,11763584 },
+  { -594563,-2514283,-32234153,12643980,12650761,14811489,665117,-12613632,-19773211,-10713562 },
+ },
+ {
+  { 30464590,-11262872,-4127476,-12734478,19835327,-7105613,-24396175,2075773,-17020157,992471 },
+  { 18357185,-6994433,7766382,16342475,-29324918,411174,14578841,8080033,-11574335,-10601610 },
+  { 19598397,10334610,12555054,2555664,18821899,-10339780,21873263,16014234,26224780,16452269 },
+ },
+ {
+  { -30223925,5145196,5944548,16385966,3976735,2009897,-11377804,-7618186,-20533829,3698650 },
+  { 14187449,3448569,-10636236,-10810935,-22663880,-3433596,7268410,-10890444,27394301,12015369 },
+  { 19695761,16087646,28032085,12999827,6817792,11427614,20244189,-1312777,-13259127,-3402461 },
+ },
+ {
+  { 30860103,12735208,-1888245,-4699734,-16974906,2256940,-8166013,12298312,-8550524,-10393462 },
+  { -5719826,-11245325,-1910649,15569035,26642876,-7587760,-5789354,-15118654,-4976164,12651793 },
+  { -2848395,9953421,11531313,-5282879,26895123,-12697089,-13118820,-16517902,9768698,-2533218 },
+ },
+ {
+  { -24719459,1894651,-287698,-4704085,15348719,-8156530,32767513,12765450,4940095,10678226 },
+  { 18860224,15980149,-18987240,-1562570,-26233012,-11071856,-7843882,13944024,-24372348,16582019 },
+  { -15504260,4970268,-29893044,4175593,-20993212,-2199756,-11704054,15444560,-11003761,7989037 },
+ },
+ {
+  { 31490452,5568061,-2412803,2182383,-32336847,4531686,-32078269,6200206,-19686113,-14800171 },
+  { -17308668,-15879940,-31522777,-2831,-32887382,16375549,8680158,-16371713,28550068,-6857132 },
+  { -28126887,-5688091,16837845,-1820458,-6850681,12700016,-30039981,4364038,1155602,5988841 },
+ },
+ {
+  { 21890435,-13272907,-12624011,12154349,-7831873,15300496,23148983,-4470481,24618407,8283181 },
+  { -33136107,-10512751,9975416,6841041,-31559793,16356536,3070187,-7025928,1466169,10740210 },
+  { -1509399,-15488185,-13503385,-10655916,32799044,909394,-13938903,-5779719,-32164649,-15327040 },
+ },
+ {
+  { 3960823,-14267803,-28026090,-15918051,-19404858,13146868,15567327,951507,-3260321,-573935 },
+  { 24740841,5052253,-30094131,8961361,25877428,6165135,-24368180,14397372,-7380369,-6144105 },
+  { -28888365,3510803,-28103278,-1158478,-11238128,-10631454,-15441463,-14453128,-1625486,-6494814 },
+ },
+},
+{
+ {
+  { 793299,-9230478,8836302,-6235707,-27360908,-2369593,33152843,-4885251,-9906200,-621852 },
+  { 5666233,525582,20782575,-8038419,-24538499,14657740,16099374,1468826,-6171428,-15186581 },
+  { -4859255,-3779343,-2917758,-6748019,7778750,11688288,-30404353,-9871238,-1558923,-9863646 },
+ },
+ {
+  { 10896332,-7719704,824275,472601,-19460308,3009587,25248958,14783338,-30581476,-15757844 },
+  { 10566929,12612572,-31944212,11118703,-12633376,12362879,21752402,8822496,24003793,14264025 },
+  { 27713862,-7355973,-11008240,9227530,27050101,2504721,23886875,-13117525,13958495,-5732453 },
+ },
+ {
+  { -23481610,4867226,-27247128,3900521,29838369,-8212291,-31889399,-10041781,7340521,-15410068 },
+  { 4646514,-8011124,-22766023,-11532654,23184553,8566613,31366726,-1381061,-15066784,-10375192 },
+  { -17270517,12723032,-16993061,14878794,21619651,-6197576,27584817,3093888,-8843694,3849921 },
+ },
+ {
+  { -9064912,2103172,25561640,-15125738,-5239824,9582958,32477045,-9017955,5002294,-15550259 },
+  { -12057553,-11177906,21115585,-13365155,8808712,-12030708,16489530,13378448,-25845716,12741426 },
+  { -5946367,10645103,-30911586,15390284,-3286982,-7118677,24306472,15852464,28834118,-7646072 },
+ },
+ {
+  { -17335748,-9107057,-24531279,9434953,-8472084,-583362,-13090771,455841,20461858,5491305 },
+  { 13669248,-16095482,-12481974,-10203039,-14569770,-11893198,-24995986,11293807,-28588204,-9421832 },
+  { 28497928,6272777,-33022994,14470570,8906179,-1225630,18504674,-14165166,29867745,-8795943 },
+ },
+ {
+  { -16207023,13517196,-27799630,-13697798,24009064,-6373891,-6367600,-13175392,22853429,-4012011 },
+  { 24191378,16712145,-13931797,15217831,14542237,1646131,18603514,-11037887,12876623,-2112447 },
+  { 17902668,4518229,-411702,-2829247,26878217,5258055,-12860753,608397,16031844,3723494 },
+ },
+ {
+  { -28632773,12763728,-20446446,7577504,33001348,-13017745,17558842,-7872890,23896954,-4314245 },
+  { -20005381,-12011952,31520464,605201,2543521,5991821,-2945064,7229064,-9919646,-8826859 },
+  { 28816045,298879,-28165016,-15920938,19000928,-1665890,-12680833,-2949325,-18051778,-2082915 },
+ },
+ {
+  { 16000882,-344896,3493092,-11447198,-29504595,-13159789,12577740,16041268,-19715240,7847707 },
+  { 10151868,10572098,27312476,7922682,14825339,4723128,-32855931,-6519018,-10020567,3852848 },
+  { -11430470,15697596,-21121557,-4420647,5386314,15063598,16514493,-15932110,29330899,-15076224 },
+ },
+},
+{
+ {
+  { -25499735,-4378794,-15222908,-6901211,16615731,2051784,3303702,15490,-27548796,12314391 },
+  { 15683520,-6003043,18109120,-9980648,15337968,-5997823,-16717435,15921866,16103996,-3731215 },
+  { -23169824,-10781249,13588192,-1628807,-3798557,-1074929,-19273607,5402699,-29815713,-9841101 },
+ },
+ {
+  { 23190676,2384583,-32714340,3462154,-29903655,-1529132,-11266856,8911517,-25205859,2739713 },
+  { 21374101,-3554250,-33524649,9874411,15377179,11831242,-33529904,6134907,4931255,11987849 },
+  { -7732,-2978858,-16223486,7277597,105524,-322051,-31480539,13861388,-30076310,10117930 },
+ },
+ {
+  { -29501170,-10744872,-26163768,13051539,-25625564,5089643,-6325503,6704079,12890019,15728940 },
+  { -21972360,-11771379,-951059,-4418840,14704840,2695116,903376,-10428139,12885167,8311031 },
+  { -17516482,5352194,10384213,-13811658,7506451,13453191,26423267,4384730,1888765,-5435404 },
+ },
+ {
+  { -25817338,-3107312,-13494599,-3182506,30896459,-13921729,-32251644,-12707869,-19464434,-3340243 },
+  { -23607977,-2665774,-526091,4651136,5765089,4618330,6092245,14845197,17151279,-9854116 },
+  { -24830458,-12733720,-15165978,10367250,-29530908,-265356,22825805,-7087279,-16866484,16176525 },
+ },
+ {
+  { -23583256,6564961,20063689,3798228,-4740178,7359225,2006182,-10363426,-28746253,-10197509 },
+  { -10626600,-4486402,-13320562,-5125317,3432136,-6393229,23632037,-1940610,32808310,1099883 },
+  { 15030977,5768825,-27451236,-2887299,-6427378,-15361371,-15277896,-6809350,2051441,-15225865 },
+ },
+ {
+  { -3362323,-7239372,7517890,9824992,23555850,295369,5148398,-14154188,-22686354,16633660 },
+  { 4577086,-16752288,13249841,-15304328,19958763,-14537274,18559670,-10759549,8402478,-9864273 },
+  { -28406330,-1051581,-26790155,-907698,-17212414,-11030789,9453451,-14980072,17983010,9967138 },
+ },
+ {
+  { -25762494,6524722,26585488,9969270,24709298,1220360,-1677990,7806337,17507396,3651560 },
+  { -10420457,-4118111,14584639,15971087,-15768321,8861010,26556809,-5574557,-18553322,-11357135 },
+  { 2839101,14284142,4029895,3472686,14402957,12689363,-26642121,8459447,-5605463,-7621941 },
+ },
+ {
+  { -4839289,-3535444,9744961,2871048,25113978,3187018,-25110813,-849066,17258084,-7977739 },
+  { 18164541,-10595176,-17154882,-1542417,19237078,-9745295,23357533,-15217008,26908270,12150756 },
+  { -30264870,-7647865,5112249,-7036672,-1499807,-6974257,43168,-5537701,-32302074,16215819 },
+ },
+},
+{
+ {
+  { -6898905,9824394,-12304779,-4401089,-31397141,-6276835,32574489,12532905,-7503072,-8675347 },
+  { -27343522,-16515468,-27151524,-10722951,946346,16291093,254968,7168080,21676107,-1943028 },
+  { 21260961,-8424752,-16831886,-11920822,-23677961,3968121,-3651949,-6215466,-3556191,-7913075 },
+ },
+ {
+  { 16544754,13250366,-16804428,15546242,-4583003,12757258,-2462308,-8680336,-18907032,-9662799 },
+  { -2415239,-15577728,18312303,4964443,-15272530,-12653564,26820651,16690659,25459437,-4564609 },
+  { -25144690,11425020,28423002,-11020557,-6144921,-15826224,9142795,-2391602,-6432418,-1644817 },
+ },
+ {
+  { -23104652,6253476,16964147,-3768872,-25113972,-12296437,-27457225,-16344658,6335692,7249989 },
+  { -30333227,13979675,7503222,-12368314,-11956721,-4621693,-30272269,2682242,25993170,-12478523 },
+  { 4364628,5930691,32304656,-10044554,-8054781,15091131,22857016,-10598955,31820368,15075278 },
+ },
+ {
+  { 31879134,-8918693,17258761,90626,-8041836,-4917709,24162788,-9650886,-17970238,12833045 },
+  { 19073683,14851414,-24403169,-11860168,7625278,11091125,-19619190,2074449,-9413939,14905377 },
+  { 24483667,-11935567,-2518866,-11547418,-1553130,15355506,-25282080,9253129,27628530,-7555480 },
+ },
+ {
+  { 17597607,8340603,19355617,552187,26198470,-3176583,4593324,-9157582,-14110875,15297016 },
+  { 510886,14337390,-31785257,16638632,6328095,2713355,-20217417,-11864220,8683221,2921426 },
+  { 18606791,11874196,27155355,-5281482,-24031742,6265446,-25178240,-1278924,4674690,13890525 },
+ },
+ {
+  { 13609624,13069022,-27372361,-13055908,24360586,9592974,14977157,9835105,4389687,288396 },
+  { 9922506,-519394,13613107,5883594,-18758345,-434263,-12304062,8317628,23388070,16052080 },
+  { 12720016,11937594,-31970060,-5028689,26900120,8561328,-20155687,-11632979,-14754271,-10812892 },
+ },
+ {
+  { 15961858,14150409,26716931,-665832,-22794328,13603569,11829573,7467844,-28822128,929275 },
+  { 11038231,-11582396,-27310482,-7316562,-10498527,-16307831,-23479533,-9371869,-21393143,2465074 },
+  { 20017163,-4323226,27915242,1529148,12396362,15675764,13817261,-9658066,2463391,-4622140 },
+ },
+ {
+  { -16358878,-12663911,-12065183,4996454,-1256422,1073572,9583558,12851107,4003896,12673717 },
+  { -1731589,-15155870,-3262930,16143082,19294135,13385325,14741514,-9103726,7903886,2348101 },
+  { 24536016,-16515207,12715592,-3862155,1511293,10047386,-3842346,-7129159,-28377538,10048127 },
+ },
+},
+{
+ {
+  { -12622226,-6204820,30718825,2591312,-10617028,12192840,18873298,-7297090,-32297756,15221632 },
+  { -26478122,-11103864,11546244,-1852483,9180880,7656409,-21343950,2095755,29769758,6593415 },
+  { -31994208,-2907461,4176912,3264766,12538965,-868111,26312345,-6118678,30958054,8292160 },
+ },
+ {
+  { 31429822,-13959116,29173532,15632448,12174511,-2760094,32808831,3977186,26143136,-3148876 },
+  { 22648901,1402143,-22799984,13746059,7936347,365344,-8668633,-1674433,-3758243,-2304625 },
+  { -15491917,8012313,-2514730,-12702462,-23965846,-10254029,-1612713,-1535569,-16664475,8194478 },
+ },
+ {
+  { 27338066,-7507420,-7414224,10140405,-19026427,-6589889,27277191,8855376,28572286,3005164 },
+  { 26287124,4821776,25476601,-4145903,-3764513,-15788984,-18008582,1182479,-26094821,-13079595 },
+  { -7171154,3178080,23970071,6201893,-17195577,-4489192,-21876275,-13982627,32208683,-1198248 },
+ },
+ {
+  { -16657702,2817643,-10286362,14811298,6024667,13349505,-27315504,-10497842,-27672585,-11539858 },
+  { 15941029,-9405932,-21367050,8062055,31876073,-238629,-15278393,-1444429,15397331,-4130193 },
+  { 8934485,-13485467,-23286397,-13423241,-32446090,14047986,31170398,-1441021,-27505566,15087184 },
+ },
+ {
+  { -18357243,-2156491,24524913,-16677868,15520427,-6360776,-15502406,11461896,16788528,-5868942 },
+  { -1947386,16013773,21750665,3714552,-17401782,-16055433,-3770287,-10323320,31322514,-11615635 },
+  { 21426655,-5650218,-13648287,-5347537,-28812189,-4920970,-18275391,-14621414,13040862,-12112948 },
+ },
+ {
+  { 11293895,12478086,-27136401,15083750,-29307421,14748872,14555558,-13417103,1613711,4896935 },
+  { -25894883,15323294,-8489791,-8057900,25967126,-13425460,2825960,-4897045,-23971776,-11267415 },
+  { -15924766,-5229880,-17443532,6410664,3622847,10243618,20615400,12405433,-23753030,-8436416 },
+ },
+ {
+  { -7091295,12556208,-20191352,9025187,-17072479,4333801,4378436,2432030,23097949,-566018 },
+  { 4565804,-16025654,20084412,-7842817,1724999,189254,24767264,10103221,-18512313,2424778 },
+  { 366633,-11976806,8173090,-6890119,30788634,5745705,-7168678,1344109,-3642553,12412659 },
+ },
+ {
+  { -24001791,7690286,14929416,-168257,-32210835,-13412986,24162697,-15326504,-3141501,11179385 },
+  { 18289522,-14724954,8056945,16430056,-21729724,7842514,-6001441,-1486897,-18684645,-11443503 },
+  { 476239,6601091,-6152790,-9723375,17503545,-4863900,27672959,13403813,11052904,5219329 },
+ },
+},
+{
+ {
+  { 20678546,-8375738,-32671898,8849123,-5009758,14574752,31186971,-3973730,9014762,-8579056 },
+  { -13644050,-10350239,-15962508,5075808,-1514661,-11534600,-33102500,9160280,8473550,-3256838 },
+  { 24900749,14435722,17209120,-15292541,-22592275,9878983,-7689309,-16335821,-24568481,11788948 },
+ },
+ {
+  { -3118155,-11395194,-13802089,14797441,9652448,-6845904,-20037437,10410733,-24568470,-1458691 },
+  { -15659161,16736706,-22467150,10215878,-9097177,7563911,11871841,-12505194,-18513325,8464118 },
+  { -23400612,8348507,-14585951,-861714,-3950205,-6373419,14325289,8628612,33313881,-8370517 },
+ },
+ {
+  { -20186973,-4967935,22367356,5271547,-1097117,-4788838,-24805667,-10236854,-8940735,-5818269 },
+  { -6948785,-1795212,-32625683,-16021179,32635414,-7374245,15989197,-12838188,28358192,-4253904 },
+  { -23561781,-2799059,-32351682,-1661963,-9147719,10429267,-16637684,4072016,-5351664,5596589 },
+ },
+ {
+  { -28236598,-3390048,12312896,6213178,3117142,16078565,29266239,2557221,1768301,15373193 },
+  { -7243358,-3246960,-4593467,-7553353,-127927,-912245,-1090902,-4504991,-24660491,3442910 },
+  { -30210571,5124043,14181784,8197961,18964734,-11939093,22597931,7176455,-18585478,13365930 },
+ },
+ {
+  { -7877390,-1499958,8324673,4690079,6261860,890446,24538107,-8570186,-9689599,-3031667 },
+  { 25008904,-10771599,-4305031,-9638010,16265036,15721635,683793,-11823784,15723479,-15163481 },
+  { -9660625,12374379,-27006999,-7026148,-7724114,-12314514,11879682,5400171,519526,-1235876 },
+ },
+ {
+  { 22258397,-16332233,-7869817,14613016,-22520255,-2950923,-20353881,7315967,16648397,7605640 },
+  { -8081308,-8464597,-8223311,9719710,19259459,-15348212,23994942,-5281555,-9468848,4763278 },
+  { -21699244,9220969,-15730624,1084137,-25476107,-2852390,31088447,-7764523,-11356529,728112 },
+ },
+ {
+  { 26047220,-11751471,-6900323,-16521798,24092068,9158119,-4273545,-12555558,-29365436,-5498272 },
+  { 17510331,-322857,5854289,8403524,17133918,-3112612,-28111007,12327945,10750447,10014012 },
+  { -10312768,3936952,9156313,-8897683,16498692,-994647,-27481051,-666732,3424691,7540221 },
+ },
+ {
+  { 30322361,-6964110,11361005,-4143317,7433304,4989748,-7071422,-16317219,-9244265,15258046 },
+  { 13054562,-2779497,19155474,469045,-12482797,4566042,5631406,2711395,1062915,-5136345 },
+  { -19240248,-11254599,-29509029,-7499965,-5835763,13005411,-6066489,12194497,32960380,1459310 },
+ },
+},
+{
+ {
+  { 19852034,7027924,23669353,10020366,8586503,-6657907,394197,-6101885,18638003,-11174937 },
+  { 31395534,15098109,26581030,8030562,-16527914,-5007134,9012486,-7584354,-6643087,-5442636 },
+  { -9192165,-2347377,-1997099,4529534,25766844,607986,-13222,9677543,-32294889,-6456008 },
+ },
+ {
+  { -2444496,-149937,29348902,8186665,1873760,12489863,-30934579,-7839692,-7852844,-8138429 },
+  { -15236356,-15433509,7766470,746860,26346930,-10221762,-27333451,10754588,-9431476,5203576 },
+  { 31834314,14135496,-770007,5159118,20917671,-16768096,-7467973,-7337524,31809243,7347066 },
+ },
+ {
+  { -9606723,-11874240,20414459,13033986,13716524,-11691881,19797970,-12211255,15192876,-2087490 },
+  { -12663563,-2181719,1168162,-3804809,26747877,-14138091,10609330,12694420,33473243,-13382104 },
+  { 33184999,11180355,15832085,-11385430,-1633671,225884,15089336,-11023903,-6135662,14480053 },
+ },
+ {
+  { 31308717,-5619998,31030840,-1897099,15674547,-6582883,5496208,13685227,27595050,8737275 },
+  { -20318852,-15150239,10933843,-16178022,8335352,-7546022,-31008351,-12610604,26498114,66511 },
+  { 22644454,-8761729,-16671776,4884562,-3105614,-13559366,30540766,-4286747,-13327787,-7515095 },
+ },
+ {
+  { -28017847,9834845,18617207,-2681312,-3401956,-13307506,8205540,13585437,-17127465,15115439 },
+  { 23711543,-672915,31206561,-8362711,6164647,-9709987,-33535882,-1426096,8236921,16492939 },
+  { -23910559,-13515526,-26299483,-4503841,25005590,-7687270,19574902,10071562,6708380,-6222424 },
+ },
+ {
+  { 2101391,-4930054,19702731,2367575,-15427167,1047675,5301017,9328700,29955601,-11678310 },
+  { 3096359,9271816,-21620864,-15521844,-14847996,-7592937,-25892142,-12635595,-9917575,6216608 },
+  { -32615849,338663,-25195611,2510422,-29213566,-13820213,24822830,-6146567,-26767480,7525079 },
+ },
+ {
+  { -23066649,-13985623,16133487,-7896178,-3389565,778788,-910336,-2782495,-19386633,11994101 },
+  { 21691500,-13624626,-641331,-14367021,3285881,-3483596,-25064666,9718258,-7477437,13381418 },
+  { 18445390,-4202236,14979846,11622458,-1727110,-3582980,23111648,-6375247,28535282,15779576 },
+ },
+ {
+  { 30098053,3089662,-9234387,16662135,-21306940,11308411,-14068454,12021730,9955285,-16303356 },
+  { 9734894,-14576830,-7473633,-9138735,2060392,11313496,-18426029,9924399,20194861,13380996 },
+  { -26378102,-7965207,-22167821,15789297,-18055342,-6168792,-1984914,15707771,26342023,10146099 },
+ },
+},
+{
+ {
+  { -26016874,-219943,21339191,-41388,19745256,-2878700,-29637280,2227040,21612326,-545728 },
+  { -13077387,1184228,23562814,-5970442,-20351244,-6348714,25764461,12243797,-20856566,11649658 },
+  { -10031494,11262626,27384172,2271902,26947504,-15997771,39944,6114064,33514190,2333242 },
+ },
+ {
+  { -21433588,-12421821,8119782,7219913,-21830522,-9016134,-6679750,-12670638,24350578,-13450001 },
+  { -4116307,-11271533,-23886186,4843615,-30088339,690623,-31536088,-10406836,8317860,12352766 },
+  { 18200138,-14475911,-33087759,-2696619,-23702521,-9102511,-23552096,-2287550,20712163,6719373 },
+ },
+ {
+  { 26656208,6075253,-7858556,1886072,-28344043,4262326,11117530,-3763210,26224235,-3297458 },
+  { -17168938,-14854097,-3395676,-16369877,-19954045,14050420,21728352,9493610,18620611,-16428628 },
+  { -13323321,13325349,11432106,5964811,18609221,6062965,-5269471,-9725556,-30701573,-16479657 },
+ },
+ {
+  { -23860538,-11233159,26961357,1640861,-32413112,-16737940,12248509,-5240639,13735342,1934062 },
+  { 25089769,6742589,17081145,-13406266,21909293,-16067981,-15136294,-3765346,-21277997,5473616 },
+  { 31883677,-7961101,1083432,-11572403,22828471,13290673,-7125085,12469656,29111212,-5451014 },
+ },
+ {
+  { 24244947,-15050407,-26262976,2791540,-14997599,16666678,24367466,6388839,-10295587,452383 },
+  { -25640782,-3417841,5217916,16224624,19987036,-4082269,-24236251,-5915248,15766062,8407814 },
+  { -20406999,13990231,15495425,16395525,5377168,15166495,-8917023,-4388953,-8067909,2276718 },
+ },
+ {
+  { 30157918,12924066,-17712050,9245753,19895028,3368142,-23827587,5096219,22740376,-7303417 },
+  { 2041139,-14256350,7783687,13876377,-25946985,-13352459,24051124,13742383,-15637599,13295222 },
+  { 33338237,-8505733,12532113,7977527,9106186,-1715251,-17720195,-4612972,-4451357,-14669444 },
+ },
+ {
+  { -20045281,5454097,-14346548,6447146,28862071,1883651,-2469266,-4141880,7770569,9620597 },
+  { 23208068,7979712,33071466,8149229,1758231,-10834995,30945528,-1694323,-33502340,-14767970 },
+  { 1439958,-16270480,-1079989,-793782,4625402,10647766,-5043801,1220118,30494170,-11440799 },
+ },
+ {
+  { -5037580,-13028295,-2970559,-3061767,15640974,-6701666,-26739026,926050,-1684339,-13333647 },
+  { 13908495,-3549272,30919928,-6273825,-21521863,7989039,9021034,9078865,3353509,4033511 },
+  { -29663431,-15113610,32259991,-344482,24295849,-12912123,23161163,8839127,27485041,7356032 },
+ },
+},
+{
+ {
+  { 9661027,705443,11980065,-5370154,-1628543,14661173,-6346142,2625015,28431036,-16771834 },
+  { -23839233,-8311415,-25945511,7480958,-17681669,-8354183,-22545972,14150565,15970762,4099461 },
+  { 29262576,16756590,26350592,-8793563,8529671,-11208050,13617293,-9937143,11465739,8317062 },
+ },
+ {
+  { -25493081,-6962928,32500200,-9419051,-23038724,-2302222,14898637,3848455,20969334,-5157516 },
+  { -20384450,-14347713,-18336405,13884722,-33039454,2842114,-21610826,-3649888,11177095,14989547 },
+  { -24496721,-11716016,16959896,2278463,12066309,10137771,13515641,2581286,-28487508,9930240 },
+ },
+ {
+  { -17751622,-2097826,16544300,-13009300,-15914807,-14949081,18345767,-13403753,16291481,-5314038 },
+  { -33229194,2553288,32678213,9875984,8534129,6889387,-9676774,6957617,4368891,9788741 },
+  { 16660756,7281060,-10830758,12911820,20108584,-8101676,-21722536,-8613148,16250552,-11111103 },
+ },
+ {
+  { -19765507,2390526,-16551031,14161980,1905286,6414907,4689584,10604807,-30190403,4782747 },
+  { -1354539,14736941,-7367442,-13292886,7710542,-14155590,-9981571,4383045,22546403,437323 },
+  { 31665577,-12180464,-16186830,1491339,-18368625,3294682,27343084,2786261,-30633590,-14097016 },
+ },
+ {
+  { -14467279,-683715,-33374107,7448552,19294360,14334329,-19690631,2355319,-19284671,-6114373 },
+  { 15121312,-15796162,6377020,-6031361,-10798111,-12957845,18952177,15496498,-29380133,11754228 },
+  { -2637277,-13483075,8488727,-14303896,12728761,-1622493,7141596,11724556,22761615,-10134141 },
+ },
+ {
+  { 16918416,11729663,-18083579,3022987,-31015732,-13339659,-28741185,-12227393,32851222,11717399 },
+  { 11166634,7338049,-6722523,4531520,-29468672,-7302055,31474879,3483633,-1193175,-4030831 },
+  { -185635,9921305,31456609,-13536438,-12013818,13348923,33142652,6546660,-19985279,-3948376 },
+ },
+ {
+  { -32460596,11266712,-11197107,-7899103,31703694,3855903,-8537131,-12833048,-30772034,-15486313 },
+  { -18006477,12709068,3991746,-6479188,-21491523,-10550425,-31135347,-16049879,10928917,3011958 },
+  { -6957757,-15594337,31696059,334240,29576716,14796075,-30831056,-12805180,18008031,10258577 },
+ },
+ {
+  { -22448644,15655569,7018479,-4410003,-30314266,-1201591,-1853465,1367120,25127874,6671743 },
+  { 29701166,-14373934,-10878120,9279288,-17568,13127210,21382910,11042292,25838796,4642684 },
+  { -20430234,14955537,-24126347,8124619,-5369288,-5990470,30468147,-13900640,18423289,4177476 },
+ },
+},
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/base.py b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/base.py
new file mode 100644
index 0000000000..84accc8580
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/base.py
@@ -0,0 +1,65 @@
+b = 256
+q = 2**255 - 19
+l = 2**252 + 27742317777372353535851937790883648493
+
+def expmod(b,e,m):
+  if e == 0: return 1
+  t = expmod(b,e/2,m)**2 % m
+  if e & 1: t = (t*b) % m
+  return t
+
+def inv(x):
+  return expmod(x,q-2,q)
+
+d = -121665 * inv(121666)
+I = expmod(2,(q-1)/4,q)
+
+def xrecover(y):
+  xx = (y*y-1) * inv(d*y*y+1)
+  x = expmod(xx,(q+3)/8,q)
+  if (x*x - xx) % q != 0: x = (x*I) % q
+  if x % 2 != 0: x = q-x
+  return x
+
+By = 4 * inv(5)
+Bx = xrecover(By)
+B = [Bx % q,By % q]
+
+def edwards(P,Q):
+  x1 = P[0]
+  y1 = P[1]
+  x2 = Q[0]
+  y2 = Q[1]
+  x3 = (x1*y2+x2*y1) * inv(1+d*x1*x2*y1*y2)
+  y3 = (y1*y2+x1*x2) * inv(1-d*x1*x2*y1*y2)
+  return [x3 % q,y3 % q]
+
+def radix255(x):
+  x = x % q
+  if x + x > q: x -= q
+  x = [x,0,0,0,0,0,0,0,0,0]
+  bits = [26,25,26,25,26,25,26,25,26,25]
+  for i in range(9):
+    carry = (x[i] + 2**(bits[i]-1)) / 2**bits[i]
+    x[i] -= carry * 2**bits[i]
+    x[i + 1] += carry
+  result = ""
+  for i in range(9):
+    result = result+str(x[i])+","
+  result = result+str(x[9])
+  return result
+
+Bi = B
+for i in range(32):
+  print "{"
+  Bij = Bi
+  for j in range(8):
+    print " {"
+    print "  {",radix255(Bij[1]+Bij[0]),"},"
+    print "  {",radix255(Bij[1]-Bij[0]),"},"
+    print "  {",radix255(2*d*Bij[0]*Bij[1]),"},"
+    Bij = edwards(Bij,Bi)
+    print " },"
+  print "},"
+  for k in range(8):
+    Bi = edwards(Bi,Bi)
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/base2.h b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/base2.h
new file mode 100644
index 0000000000..8c538440ff
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/base2.h
@@ -0,0 +1,40 @@
+ {
+  { 25967493,-14356035,29566456,3660896,-12694345,4014787,27544626,-11754271,-6079156,2047605 },
+  { -12545711,934262,-2722910,3049990,-727428,9406986,12720692,5043384,19500929,-15469378 },
+  { -8738181,4489570,9688441,-14785194,10184609,-12363380,29287919,11864899,-24514362,-4438546 },
+ },
+ {
+  { 15636291,-9688557,24204773,-7912398,616977,-16685262,27787600,-14772189,28944400,-1550024 },
+  { 16568933,4717097,-11556148,-1102322,15682896,-11807043,16354577,-11775962,7689662,11199574 },
+  { 30464156,-5976125,-11779434,-15670865,23220365,15915852,7512774,10017326,-17749093,-9920357 },
+ },
+ {
+  { 10861363,11473154,27284546,1981175,-30064349,12577861,32867885,14515107,-15438304,10819380 },
+  { 4708026,6336745,20377586,9066809,-11272109,6594696,-25653668,12483688,-12668491,5581306 },
+  { 19563160,16186464,-29386857,4097519,10237984,-4348115,28542350,13850243,-23678021,-15815942 },
+ },
+ {
+  { 5153746,9909285,1723747,-2777874,30523605,5516873,19480852,5230134,-23952439,-15175766 },
+  { -30269007,-3463509,7665486,10083793,28475525,1649722,20654025,16520125,30598449,7715701 },
+  { 28881845,14381568,9657904,3680757,-20181635,7843316,-31400660,1370708,29794553,-1409300 },
+ },
+ {
+  { -22518993,-6692182,14201702,-8745502,-23510406,8844726,18474211,-1361450,-13062696,13821877 },
+  { -6455177,-7839871,3374702,-4740862,-27098617,-10571707,31655028,-7212327,18853322,-14220951 },
+  { 4566830,-12963868,-28974889,-12240689,-7602672,-2830569,-8514358,-10431137,2207753,-3209784 },
+ },
+ {
+  { -25154831,-4185821,29681144,7868801,-6854661,-9423865,-12437364,-663000,-31111463,-16132436 },
+  { 25576264,-2703214,7349804,-11814844,16472782,9300885,3844789,15725684,171356,6466918 },
+  { 23103977,13316479,9739013,-16149481,817875,-15038942,8965339,-14088058,-30714912,16193877 },
+ },
+ {
+  { -33521811,3180713,-2394130,14003687,-16903474,-16270840,17238398,4729455,-18074513,9256800 },
+  { -25182317,-4174131,32336398,5036987,-21236817,11360617,22616405,9761698,-19827198,630305 },
+  { -13720693,2639453,-24237460,-7406481,9494427,-5774029,-6554551,-15960994,-2449256,-14291300 },
+ },
+ {
+  { -3151181,-5046075,9282714,6866145,-31907062,-863023,-18940575,15033784,25105118,-7894876 },
+  { -24326370,15950226,-31801215,-14592823,-11662737,-5090925,1573892,-2625887,2198790,-15804619 },
+  { -3099351,10324967,-2241613,7453183,-5446979,-2735503,-13812022,-16236442,-32461234,-12290683 },
+ },
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/base2.py b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/base2.py
new file mode 100644
index 0000000000..5e4e8739d0
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/base2.py
@@ -0,0 +1,60 @@
+b = 256
+q = 2**255 - 19
+l = 2**252 + 27742317777372353535851937790883648493
+
+def expmod(b,e,m):
+  if e == 0: return 1
+  t = expmod(b,e/2,m)**2 % m
+  if e & 1: t = (t*b) % m
+  return t
+
+def inv(x):
+  return expmod(x,q-2,q)
+
+d = -121665 * inv(121666)
+I = expmod(2,(q-1)/4,q)
+
+def xrecover(y):
+  xx = (y*y-1) * inv(d*y*y+1)
+  x = expmod(xx,(q+3)/8,q)
+  if (x*x - xx) % q != 0: x = (x*I) % q
+  if x % 2 != 0: x = q-x
+  return x
+
+By = 4 * inv(5)
+Bx = xrecover(By)
+B = [Bx % q,By % q]
+
+def edwards(P,Q):
+  x1 = P[0]
+  y1 = P[1]
+  x2 = Q[0]
+  y2 = Q[1]
+  x3 = (x1*y2+x2*y1) * inv(1+d*x1*x2*y1*y2)
+  y3 = (y1*y2+x1*x2) * inv(1-d*x1*x2*y1*y2)
+  return [x3 % q,y3 % q]
+
+def radix255(x):
+  x = x % q
+  if x + x > q: x -= q
+  x = [x,0,0,0,0,0,0,0,0,0]
+  bits = [26,25,26,25,26,25,26,25,26,25]
+  for i in range(9):
+    carry = (x[i] + 2**(bits[i]-1)) / 2**bits[i]
+    x[i] -= carry * 2**bits[i]
+    x[i + 1] += carry
+  result = ""
+  for i in range(9):
+    result = result+str(x[i])+","
+  result = result+str(x[9])
+  return result
+
+Bi = B
+
+for i in range(8):
+  print " {"
+  print "  {",radix255(Bi[1]+Bi[0]),"},"
+  print "  {",radix255(Bi[1]-Bi[0]),"},"
+  print "  {",radix255(2*d*Bi[0]*Bi[1]),"},"
+  print " },"
+  Bi = edwards(B,edwards(B,Bi))
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/crypto-ops.h b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/crypto-ops.h
new file mode 100644
index 0000000000..b432efade6
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/crypto-ops.h
@@ -0,0 +1,145 @@
+// 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
+
+#pragma once
+
+/* From fe.h */
+
+typedef int32_t fe[10];
+
+/* From ge.h */
+
+typedef struct {
+  fe X;
+  fe Y;
+  fe Z;
+} ge_p2;
+
+typedef struct {
+  fe X;
+  fe Y;
+  fe Z;
+  fe T;
+} ge_p3;
+
+typedef struct {
+  fe X;
+  fe Y;
+  fe Z;
+  fe T;
+} ge_p1p1;
+
+typedef struct {
+  fe yplusx;
+  fe yminusx;
+  fe xy2d;
+} ge_precomp;
+
+typedef struct {
+  fe YplusX;
+  fe YminusX;
+  fe Z;
+  fe T2d;
+} ge_cached;
+
+/* From ge_add.c */
+
+void ge_add(ge_p1p1 *, const ge_p3 *, const ge_cached *);
+
+/* From ge_double_scalarmult.c, modified */
+
+typedef ge_cached ge_dsmp[8];
+extern const ge_precomp ge_Bi[8];
+void ge_dsm_precomp(ge_dsmp r, const ge_p3 *s);
+void ge_double_scalarmult_base_vartime(ge_p2 *, const unsigned char *, const ge_p3 *, const unsigned char *);
+
+/* From ge_frombytes.c, modified */
+
+extern const fe fe_sqrtm1;
+extern const fe fe_d;
+int ge_frombytes_vartime(ge_p3 *, const unsigned char *);
+
+/* From ge_p1p1_to_p2.c */
+
+void ge_p1p1_to_p2(ge_p2 *, const ge_p1p1 *);
+
+/* From ge_p1p1_to_p3.c */
+
+void ge_p1p1_to_p3(ge_p3 *, const ge_p1p1 *);
+
+/* From ge_p2_dbl.c */
+
+void ge_p2_dbl(ge_p1p1 *, const ge_p2 *);
+
+/* From ge_p3_to_cached.c */
+
+extern const fe fe_d2;
+void ge_p3_to_cached(ge_cached *, const ge_p3 *);
+
+/* From ge_p3_to_p2.c */
+
+void ge_p3_to_p2(ge_p2 *, const ge_p3 *);
+
+/* From ge_p3_tobytes.c */
+
+void ge_p3_tobytes(unsigned char *, const ge_p3 *);
+
+/* From ge_scalarmult_base.c */
+
+extern const ge_precomp ge_base[32][8];
+void ge_scalarmult_base(ge_p3 *, const unsigned char *);
+
+/* From ge_tobytes.c */
+
+void ge_tobytes(unsigned char *, const ge_p2 *);
+
+/* From sc_reduce.c */
+
+void sc_reduce(unsigned char *);
+
+/* New code */
+
+void ge_scalarmult(ge_p2 *, const unsigned char *, const ge_p3 *);
+void ge_double_scalarmult_precomp_vartime(ge_p2 *, const unsigned char *, const ge_p3 *, const unsigned char *, const ge_dsmp);
+void ge_mul8(ge_p1p1 *, const ge_p2 *);
+extern const fe fe_ma2;
+extern const fe fe_ma;
+extern const fe fe_fffb1;
+extern const fe fe_fffb2;
+extern const fe fe_fffb3;
+extern const fe fe_fffb4;
+void ge_fromfe_frombytes_vartime(ge_p2 *, const unsigned char *);
+void sc_0(unsigned char *);
+void sc_reduce32(unsigned char *);
+void sc_add(unsigned char *, const unsigned char *, const unsigned char *);
+void sc_sub(unsigned char *, const unsigned char *, const unsigned char *);
+void sc_mulsub(unsigned char *, const unsigned char *, const unsigned char *, const unsigned char *);
+int sc_check(const unsigned char *);
+int sc_isnonzero(const unsigned char *); /* Doesn't normalize */
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/d.h b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/d.h
new file mode 100644
index 0000000000..e25f578350
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/d.h
@@ -0,0 +1 @@
+-10913610,13857413,-15372611,6949391,114729,-8787816,-6275908,-3247719,-18696448,-12055116
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/d.py b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/d.py
new file mode 100644
index 0000000000..8995bb86a3
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/d.py
@@ -0,0 +1,28 @@
+q = 2**255 - 19
+
+def expmod(b,e,m):
+  if e == 0: return 1
+  t = expmod(b,e/2,m)**2 % m
+  if e & 1: t = (t*b) % m
+  return t
+
+def inv(x):
+  return expmod(x,q-2,q)
+
+def radix255(x):
+  x = x % q
+  if x + x > q: x -= q
+  x = [x,0,0,0,0,0,0,0,0,0]
+  bits = [26,25,26,25,26,25,26,25,26,25]
+  for i in range(9):
+    carry = (x[i] + 2**(bits[i]-1)) / 2**bits[i]
+    x[i] -= carry * 2**bits[i]
+    x[i + 1] += carry
+  result = ""
+  for i in range(9):
+    result = result+str(x[i])+","
+  result = result+str(x[9])
+  return result
+
+d = -121665 * inv(121666)
+print radix255(d)
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/d2.h b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/d2.h
new file mode 100644
index 0000000000..01aaec7512
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/d2.h
@@ -0,0 +1 @@
+-21827239,-5839606,-30745221,13898782,229458,15978800,-12551817,-6495438,29715968,9444199
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/d2.py b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/d2.py
new file mode 100644
index 0000000000..79841758be
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/d2.py
@@ -0,0 +1,28 @@
+q = 2**255 - 19
+
+def expmod(b,e,m):
+  if e == 0: return 1
+  t = expmod(b,e/2,m)**2 % m
+  if e & 1: t = (t*b) % m
+  return t
+
+def inv(x):
+  return expmod(x,q-2,q)
+
+def radix255(x):
+  x = x % q
+  if x + x > q: x -= q
+  x = [x,0,0,0,0,0,0,0,0,0]
+  bits = [26,25,26,25,26,25,26,25,26,25]
+  for i in range(9):
+    carry = (x[i] + 2**(bits[i]-1)) / 2**bits[i]
+    x[i] -= carry * 2**bits[i]
+    x[i + 1] += carry
+  result = ""
+  for i in range(9):
+    result = result+str(x[i])+","
+  result = result+str(x[9])
+  return result
+
+d = -121665 * inv(121666)
+print radix255(d*2)
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/description b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/description
new file mode 100644
index 0000000000..fadc9f9afb
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/description
@@ -0,0 +1,7 @@
+shen_ed25519_ref10
+MakeCryptoOps.py makes crypto-ops.c in the Monero source from the ref10 implementation
+
+EdDSA signatures using Curve25519
+from http://hyperelliptic.org/ebats/supercop-20141124.tar.bz2
+
+Commented / combined by Shen Noether, Monero Research Lab
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/designers b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/designers
new file mode 100644
index 0000000000..8ee9c735fc
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/designers
@@ -0,0 +1,9 @@
+ref10:
+Daniel J. Bernstein
+Niels Duif
+Tanja Lange
+Peter Schwabe
+Bo-Yin Yang
+
+MakeCryptoOps.py:
+Shen Noether, Monero Research Labs
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe.h b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe.h
new file mode 100644
index 0000000000..60c308ba46
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe.h
@@ -0,0 +1,56 @@
+#ifndef FE_H
+#define FE_H
+
+#include "crypto_int32.h"
+
+typedef crypto_int32 fe[10];
+
+/*
+fe means field element.
+Here the field is \Z/(2^255-19).
+An element t, entries t[0]...t[9], represents the integer
+t[0]+2^26 t[1]+2^51 t[2]+2^77 t[3]+2^102 t[4]+...+2^230 t[9].
+Bounds on each t[i] vary depending on context.
+*/
+
+#define fe_frombytes crypto_sign_ed25519_ref10_fe_frombytes
+#define fe_tobytes crypto_sign_ed25519_ref10_fe_tobytes
+#define fe_copy crypto_sign_ed25519_ref10_fe_copy
+#define fe_isnonzero crypto_sign_ed25519_ref10_fe_isnonzero
+#define fe_isnegative crypto_sign_ed25519_ref10_fe_isnegative
+#define fe_0 crypto_sign_ed25519_ref10_fe_0
+#define fe_1 crypto_sign_ed25519_ref10_fe_1
+#define fe_cswap crypto_sign_ed25519_ref10_fe_cswap
+#define fe_cmov crypto_sign_ed25519_ref10_fe_cmov
+#define fe_add crypto_sign_ed25519_ref10_fe_add
+#define fe_sub crypto_sign_ed25519_ref10_fe_sub
+#define fe_neg crypto_sign_ed25519_ref10_fe_neg
+#define fe_mul crypto_sign_ed25519_ref10_fe_mul
+#define fe_sq crypto_sign_ed25519_ref10_fe_sq
+#define fe_sq2 crypto_sign_ed25519_ref10_fe_sq2
+#define fe_mul121666 crypto_sign_ed25519_ref10_fe_mul121666
+#define fe_invert crypto_sign_ed25519_ref10_fe_invert
+#define fe_pow22523 crypto_sign_ed25519_ref10_fe_pow22523
+
+extern void fe_frombytes(fe,const unsigned char *);
+extern void fe_tobytes(unsigned char *,const fe);
+
+extern void fe_copy(fe,const fe);
+extern int fe_isnonzero(const fe);
+extern int fe_isnegative(const fe);
+extern void fe_0(fe);
+extern void fe_1(fe);
+extern void fe_cswap(fe,fe,unsigned int);
+extern void fe_cmov(fe,const fe,unsigned int);
+
+extern void fe_add(fe,const fe,const fe);
+extern void fe_sub(fe,const fe,const fe);
+extern void fe_neg(fe,const fe);
+extern void fe_mul(fe,const fe,const fe);
+extern void fe_sq(fe,const fe);
+extern void fe_sq2(fe,const fe);
+extern void fe_mul121666(fe,const fe);
+extern void fe_invert(fe,const fe);
+extern void fe_pow22523(fe,const fe);
+
+#endif
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_0.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_0.c
new file mode 100644
index 0000000000..ec879d7337
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_0.c
@@ -0,0 +1,19 @@
+#include "fe.h"
+
+/*
+h = 0
+*/
+
+void fe_0(fe h)
+{
+  h[0] = 0;
+  h[1] = 0;
+  h[2] = 0;
+  h[3] = 0;
+  h[4] = 0;
+  h[5] = 0;
+  h[6] = 0;
+  h[7] = 0;
+  h[8] = 0;
+  h[9] = 0;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_1.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_1.c
new file mode 100644
index 0000000000..8cf7784844
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_1.c
@@ -0,0 +1,19 @@
+#include "fe.h"
+
+/*
+h = 1
+*/
+
+void fe_1(fe h)
+{
+  h[0] = 1;
+  h[1] = 0;
+  h[2] = 0;
+  h[3] = 0;
+  h[4] = 0;
+  h[5] = 0;
+  h[6] = 0;
+  h[7] = 0;
+  h[8] = 0;
+  h[9] = 0;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_add.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_add.c
new file mode 100644
index 0000000000..e6a81da202
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_add.c
@@ -0,0 +1,57 @@
+#include "fe.h"
+
+/*
+h = f + g
+Can overlap h with f or g.
+
+Preconditions:
+   |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+   |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+
+Postconditions:
+   |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+void fe_add(fe h,const fe f,const fe g)
+{
+  crypto_int32 f0 = f[0];
+  crypto_int32 f1 = f[1];
+  crypto_int32 f2 = f[2];
+  crypto_int32 f3 = f[3];
+  crypto_int32 f4 = f[4];
+  crypto_int32 f5 = f[5];
+  crypto_int32 f6 = f[6];
+  crypto_int32 f7 = f[7];
+  crypto_int32 f8 = f[8];
+  crypto_int32 f9 = f[9];
+  crypto_int32 g0 = g[0];
+  crypto_int32 g1 = g[1];
+  crypto_int32 g2 = g[2];
+  crypto_int32 g3 = g[3];
+  crypto_int32 g4 = g[4];
+  crypto_int32 g5 = g[5];
+  crypto_int32 g6 = g[6];
+  crypto_int32 g7 = g[7];
+  crypto_int32 g8 = g[8];
+  crypto_int32 g9 = g[9];
+  crypto_int32 h0 = f0 + g0;
+  crypto_int32 h1 = f1 + g1;
+  crypto_int32 h2 = f2 + g2;
+  crypto_int32 h3 = f3 + g3;
+  crypto_int32 h4 = f4 + g4;
+  crypto_int32 h5 = f5 + g5;
+  crypto_int32 h6 = f6 + g6;
+  crypto_int32 h7 = f7 + g7;
+  crypto_int32 h8 = f8 + g8;
+  crypto_int32 h9 = f9 + g9;
+  h[0] = h0;
+  h[1] = h1;
+  h[2] = h2;
+  h[3] = h3;
+  h[4] = h4;
+  h[5] = h5;
+  h[6] = h6;
+  h[7] = h7;
+  h[8] = h8;
+  h[9] = h9;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_cmov.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_cmov.c
new file mode 100644
index 0000000000..8ca584fb19
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_cmov.c
@@ -0,0 +1,63 @@
+#include "fe.h"
+
+/*
+Replace (f,g) with (g,g) if b == 1;
+replace (f,g) with (f,g) if b == 0.
+
+Preconditions: b in {0,1}.
+*/
+
+void fe_cmov(fe f,const fe g,unsigned int b)
+{
+  crypto_int32 f0 = f[0];
+  crypto_int32 f1 = f[1];
+  crypto_int32 f2 = f[2];
+  crypto_int32 f3 = f[3];
+  crypto_int32 f4 = f[4];
+  crypto_int32 f5 = f[5];
+  crypto_int32 f6 = f[6];
+  crypto_int32 f7 = f[7];
+  crypto_int32 f8 = f[8];
+  crypto_int32 f9 = f[9];
+  crypto_int32 g0 = g[0];
+  crypto_int32 g1 = g[1];
+  crypto_int32 g2 = g[2];
+  crypto_int32 g3 = g[3];
+  crypto_int32 g4 = g[4];
+  crypto_int32 g5 = g[5];
+  crypto_int32 g6 = g[6];
+  crypto_int32 g7 = g[7];
+  crypto_int32 g8 = g[8];
+  crypto_int32 g9 = g[9];
+  crypto_int32 x0 = f0 ^ g0;
+  crypto_int32 x1 = f1 ^ g1;
+  crypto_int32 x2 = f2 ^ g2;
+  crypto_int32 x3 = f3 ^ g3;
+  crypto_int32 x4 = f4 ^ g4;
+  crypto_int32 x5 = f5 ^ g5;
+  crypto_int32 x6 = f6 ^ g6;
+  crypto_int32 x7 = f7 ^ g7;
+  crypto_int32 x8 = f8 ^ g8;
+  crypto_int32 x9 = f9 ^ g9;
+  b = -b;
+  x0 &= b;
+  x1 &= b;
+  x2 &= b;
+  x3 &= b;
+  x4 &= b;
+  x5 &= b;
+  x6 &= b;
+  x7 &= b;
+  x8 &= b;
+  x9 &= b;
+  f[0] = f0 ^ x0;
+  f[1] = f1 ^ x1;
+  f[2] = f2 ^ x2;
+  f[3] = f3 ^ x3;
+  f[4] = f4 ^ x4;
+  f[5] = f5 ^ x5;
+  f[6] = f6 ^ x6;
+  f[7] = f7 ^ x7;
+  f[8] = f8 ^ x8;
+  f[9] = f9 ^ x9;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_copy.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_copy.c
new file mode 100644
index 0000000000..9c5bf865a2
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_copy.c
@@ -0,0 +1,29 @@
+#include "fe.h"
+
+/*
+h = f
+*/
+
+void fe_copy(fe h,const fe f)
+{
+  crypto_int32 f0 = f[0];
+  crypto_int32 f1 = f[1];
+  crypto_int32 f2 = f[2];
+  crypto_int32 f3 = f[3];
+  crypto_int32 f4 = f[4];
+  crypto_int32 f5 = f[5];
+  crypto_int32 f6 = f[6];
+  crypto_int32 f7 = f[7];
+  crypto_int32 f8 = f[8];
+  crypto_int32 f9 = f[9];
+  h[0] = f0;
+  h[1] = f1;
+  h[2] = f2;
+  h[3] = f3;
+  h[4] = f4;
+  h[5] = f5;
+  h[6] = f6;
+  h[7] = f7;
+  h[8] = f8;
+  h[9] = f9;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_frombytes.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_frombytes.c
new file mode 100644
index 0000000000..5c17917487
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_frombytes.c
@@ -0,0 +1,73 @@
+#include "fe.h"
+#include "crypto_int64.h"
+#include "crypto_uint64.h"
+
+static crypto_uint64 load_3(const unsigned char *in)
+{
+  crypto_uint64 result;
+  result = (crypto_uint64) in[0];
+  result |= ((crypto_uint64) in[1]) << 8;
+  result |= ((crypto_uint64) in[2]) << 16;
+  return result;
+}
+
+static crypto_uint64 load_4(const unsigned char *in)
+{
+  crypto_uint64 result;
+  result = (crypto_uint64) in[0];
+  result |= ((crypto_uint64) in[1]) << 8;
+  result |= ((crypto_uint64) in[2]) << 16;
+  result |= ((crypto_uint64) in[3]) << 24;
+  return result;
+}
+
+/*
+Ignores top bit of h.
+*/
+
+void fe_frombytes(fe h,const unsigned char *s)
+{
+  crypto_int64 h0 = load_4(s);
+  crypto_int64 h1 = load_3(s + 4) << 6;
+  crypto_int64 h2 = load_3(s + 7) << 5;
+  crypto_int64 h3 = load_3(s + 10) << 3;
+  crypto_int64 h4 = load_3(s + 13) << 2;
+  crypto_int64 h5 = load_4(s + 16);
+  crypto_int64 h6 = load_3(s + 20) << 7;
+  crypto_int64 h7 = load_3(s + 23) << 5;
+  crypto_int64 h8 = load_3(s + 26) << 4;
+  crypto_int64 h9 = (load_3(s + 29) & 8388607) << 2;
+  crypto_int64 carry0;
+  crypto_int64 carry1;
+  crypto_int64 carry2;
+  crypto_int64 carry3;
+  crypto_int64 carry4;
+  crypto_int64 carry5;
+  crypto_int64 carry6;
+  crypto_int64 carry7;
+  crypto_int64 carry8;
+  crypto_int64 carry9;
+
+  carry9 = (h9 + (crypto_int64) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+  carry1 = (h1 + (crypto_int64) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+  carry3 = (h3 + (crypto_int64) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+  carry5 = (h5 + (crypto_int64) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+  carry7 = (h7 + (crypto_int64) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+  carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+  carry2 = (h2 + (crypto_int64) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+  carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+  carry6 = (h6 + (crypto_int64) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+  carry8 = (h8 + (crypto_int64) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+  h[0] = h0;
+  h[1] = h1;
+  h[2] = h2;
+  h[3] = h3;
+  h[4] = h4;
+  h[5] = h5;
+  h[6] = h6;
+  h[7] = h7;
+  h[8] = h8;
+  h[9] = h9;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_invert.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_invert.c
new file mode 100644
index 0000000000..bcfdb8ff87
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_invert.c
@@ -0,0 +1,14 @@
+#include "fe.h"
+
+void fe_invert(fe out,const fe z)
+{
+  fe t0;
+  fe t1;
+  fe t2;
+  fe t3;
+  int i;
+
+#include "pow225521.h"
+
+  return;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_isnegative.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_isnegative.c
new file mode 100644
index 0000000000..3b2c8b8d52
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_isnegative.c
@@ -0,0 +1,16 @@
+#include "fe.h"
+
+/*
+return 1 if f is in {1,3,5,...,q-2}
+return 0 if f is in {0,2,4,...,q-1}
+
+Preconditions:
+   |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+int fe_isnegative(const fe f)
+{
+  unsigned char s[32];
+  fe_tobytes(s,f);
+  return s[0] & 1;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_isnonzero.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_isnonzero.c
new file mode 100644
index 0000000000..47568001ce
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_isnonzero.c
@@ -0,0 +1,19 @@
+#include "fe.h"
+#include "crypto_verify_32.h"
+
+/*
+return 1 if f == 0
+return 0 if f != 0
+
+Preconditions:
+   |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+static const unsigned char zero[32];
+
+int fe_isnonzero(const fe f)
+{
+  unsigned char s[32];
+  fe_tobytes(s,f);
+  return crypto_verify_32(s,zero);
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_mul.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_mul.c
new file mode 100644
index 0000000000..26ca8b3682
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_mul.c
@@ -0,0 +1,253 @@
+#include "fe.h"
+#include "crypto_int64.h"
+
+/*
+h = f * g
+Can overlap h with f or g.
+
+Preconditions:
+   |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+   |g| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+
+Postconditions:
+   |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
+*/
+
+/*
+Notes on implementation strategy:
+
+Using schoolbook multiplication.
+Karatsuba would save a little in some cost models.
+
+Most multiplications by 2 and 19 are 32-bit precomputations;
+cheaper than 64-bit postcomputations.
+
+There is one remaining multiplication by 19 in the carry chain;
+one *19 precomputation can be merged into this,
+but the resulting data flow is considerably less clean.
+
+There are 12 carries below.
+10 of them are 2-way parallelizable and vectorizable.
+Can get away with 11 carries, but then data flow is much deeper.
+
+With tighter constraints on inputs can squeeze carries into int32.
+*/
+
+void fe_mul(fe h,const fe f,const fe g)
+{
+  crypto_int32 f0 = f[0];
+  crypto_int32 f1 = f[1];
+  crypto_int32 f2 = f[2];
+  crypto_int32 f3 = f[3];
+  crypto_int32 f4 = f[4];
+  crypto_int32 f5 = f[5];
+  crypto_int32 f6 = f[6];
+  crypto_int32 f7 = f[7];
+  crypto_int32 f8 = f[8];
+  crypto_int32 f9 = f[9];
+  crypto_int32 g0 = g[0];
+  crypto_int32 g1 = g[1];
+  crypto_int32 g2 = g[2];
+  crypto_int32 g3 = g[3];
+  crypto_int32 g4 = g[4];
+  crypto_int32 g5 = g[5];
+  crypto_int32 g6 = g[6];
+  crypto_int32 g7 = g[7];
+  crypto_int32 g8 = g[8];
+  crypto_int32 g9 = g[9];
+  crypto_int32 g1_19 = 19 * g1; /* 1.959375*2^29 */
+  crypto_int32 g2_19 = 19 * g2; /* 1.959375*2^30; still ok */
+  crypto_int32 g3_19 = 19 * g3;
+  crypto_int32 g4_19 = 19 * g4;
+  crypto_int32 g5_19 = 19 * g5;
+  crypto_int32 g6_19 = 19 * g6;
+  crypto_int32 g7_19 = 19 * g7;
+  crypto_int32 g8_19 = 19 * g8;
+  crypto_int32 g9_19 = 19 * g9;
+  crypto_int32 f1_2 = 2 * f1;
+  crypto_int32 f3_2 = 2 * f3;
+  crypto_int32 f5_2 = 2 * f5;
+  crypto_int32 f7_2 = 2 * f7;
+  crypto_int32 f9_2 = 2 * f9;
+  crypto_int64 f0g0    = f0   * (crypto_int64) g0;
+  crypto_int64 f0g1    = f0   * (crypto_int64) g1;
+  crypto_int64 f0g2    = f0   * (crypto_int64) g2;
+  crypto_int64 f0g3    = f0   * (crypto_int64) g3;
+  crypto_int64 f0g4    = f0   * (crypto_int64) g4;
+  crypto_int64 f0g5    = f0   * (crypto_int64) g5;
+  crypto_int64 f0g6    = f0   * (crypto_int64) g6;
+  crypto_int64 f0g7    = f0   * (crypto_int64) g7;
+  crypto_int64 f0g8    = f0   * (crypto_int64) g8;
+  crypto_int64 f0g9    = f0   * (crypto_int64) g9;
+  crypto_int64 f1g0    = f1   * (crypto_int64) g0;
+  crypto_int64 f1g1_2  = f1_2 * (crypto_int64) g1;
+  crypto_int64 f1g2    = f1   * (crypto_int64) g2;
+  crypto_int64 f1g3_2  = f1_2 * (crypto_int64) g3;
+  crypto_int64 f1g4    = f1   * (crypto_int64) g4;
+  crypto_int64 f1g5_2  = f1_2 * (crypto_int64) g5;
+  crypto_int64 f1g6    = f1   * (crypto_int64) g6;
+  crypto_int64 f1g7_2  = f1_2 * (crypto_int64) g7;
+  crypto_int64 f1g8    = f1   * (crypto_int64) g8;
+  crypto_int64 f1g9_38 = f1_2 * (crypto_int64) g9_19;
+  crypto_int64 f2g0    = f2   * (crypto_int64) g0;
+  crypto_int64 f2g1    = f2   * (crypto_int64) g1;
+  crypto_int64 f2g2    = f2   * (crypto_int64) g2;
+  crypto_int64 f2g3    = f2   * (crypto_int64) g3;
+  crypto_int64 f2g4    = f2   * (crypto_int64) g4;
+  crypto_int64 f2g5    = f2   * (crypto_int64) g5;
+  crypto_int64 f2g6    = f2   * (crypto_int64) g6;
+  crypto_int64 f2g7    = f2   * (crypto_int64) g7;
+  crypto_int64 f2g8_19 = f2   * (crypto_int64) g8_19;
+  crypto_int64 f2g9_19 = f2   * (crypto_int64) g9_19;
+  crypto_int64 f3g0    = f3   * (crypto_int64) g0;
+  crypto_int64 f3g1_2  = f3_2 * (crypto_int64) g1;
+  crypto_int64 f3g2    = f3   * (crypto_int64) g2;
+  crypto_int64 f3g3_2  = f3_2 * (crypto_int64) g3;
+  crypto_int64 f3g4    = f3   * (crypto_int64) g4;
+  crypto_int64 f3g5_2  = f3_2 * (crypto_int64) g5;
+  crypto_int64 f3g6    = f3   * (crypto_int64) g6;
+  crypto_int64 f3g7_38 = f3_2 * (crypto_int64) g7_19;
+  crypto_int64 f3g8_19 = f3   * (crypto_int64) g8_19;
+  crypto_int64 f3g9_38 = f3_2 * (crypto_int64) g9_19;
+  crypto_int64 f4g0    = f4   * (crypto_int64) g0;
+  crypto_int64 f4g1    = f4   * (crypto_int64) g1;
+  crypto_int64 f4g2    = f4   * (crypto_int64) g2;
+  crypto_int64 f4g3    = f4   * (crypto_int64) g3;
+  crypto_int64 f4g4    = f4   * (crypto_int64) g4;
+  crypto_int64 f4g5    = f4   * (crypto_int64) g5;
+  crypto_int64 f4g6_19 = f4   * (crypto_int64) g6_19;
+  crypto_int64 f4g7_19 = f4   * (crypto_int64) g7_19;
+  crypto_int64 f4g8_19 = f4   * (crypto_int64) g8_19;
+  crypto_int64 f4g9_19 = f4   * (crypto_int64) g9_19;
+  crypto_int64 f5g0    = f5   * (crypto_int64) g0;
+  crypto_int64 f5g1_2  = f5_2 * (crypto_int64) g1;
+  crypto_int64 f5g2    = f5   * (crypto_int64) g2;
+  crypto_int64 f5g3_2  = f5_2 * (crypto_int64) g3;
+  crypto_int64 f5g4    = f5   * (crypto_int64) g4;
+  crypto_int64 f5g5_38 = f5_2 * (crypto_int64) g5_19;
+  crypto_int64 f5g6_19 = f5   * (crypto_int64) g6_19;
+  crypto_int64 f5g7_38 = f5_2 * (crypto_int64) g7_19;
+  crypto_int64 f5g8_19 = f5   * (crypto_int64) g8_19;
+  crypto_int64 f5g9_38 = f5_2 * (crypto_int64) g9_19;
+  crypto_int64 f6g0    = f6   * (crypto_int64) g0;
+  crypto_int64 f6g1    = f6   * (crypto_int64) g1;
+  crypto_int64 f6g2    = f6   * (crypto_int64) g2;
+  crypto_int64 f6g3    = f6   * (crypto_int64) g3;
+  crypto_int64 f6g4_19 = f6   * (crypto_int64) g4_19;
+  crypto_int64 f6g5_19 = f6   * (crypto_int64) g5_19;
+  crypto_int64 f6g6_19 = f6   * (crypto_int64) g6_19;
+  crypto_int64 f6g7_19 = f6   * (crypto_int64) g7_19;
+  crypto_int64 f6g8_19 = f6   * (crypto_int64) g8_19;
+  crypto_int64 f6g9_19 = f6   * (crypto_int64) g9_19;
+  crypto_int64 f7g0    = f7   * (crypto_int64) g0;
+  crypto_int64 f7g1_2  = f7_2 * (crypto_int64) g1;
+  crypto_int64 f7g2    = f7   * (crypto_int64) g2;
+  crypto_int64 f7g3_38 = f7_2 * (crypto_int64) g3_19;
+  crypto_int64 f7g4_19 = f7   * (crypto_int64) g4_19;
+  crypto_int64 f7g5_38 = f7_2 * (crypto_int64) g5_19;
+  crypto_int64 f7g6_19 = f7   * (crypto_int64) g6_19;
+  crypto_int64 f7g7_38 = f7_2 * (crypto_int64) g7_19;
+  crypto_int64 f7g8_19 = f7   * (crypto_int64) g8_19;
+  crypto_int64 f7g9_38 = f7_2 * (crypto_int64) g9_19;
+  crypto_int64 f8g0    = f8   * (crypto_int64) g0;
+  crypto_int64 f8g1    = f8   * (crypto_int64) g1;
+  crypto_int64 f8g2_19 = f8   * (crypto_int64) g2_19;
+  crypto_int64 f8g3_19 = f8   * (crypto_int64) g3_19;
+  crypto_int64 f8g4_19 = f8   * (crypto_int64) g4_19;
+  crypto_int64 f8g5_19 = f8   * (crypto_int64) g5_19;
+  crypto_int64 f8g6_19 = f8   * (crypto_int64) g6_19;
+  crypto_int64 f8g7_19 = f8   * (crypto_int64) g7_19;
+  crypto_int64 f8g8_19 = f8   * (crypto_int64) g8_19;
+  crypto_int64 f8g9_19 = f8   * (crypto_int64) g9_19;
+  crypto_int64 f9g0    = f9   * (crypto_int64) g0;
+  crypto_int64 f9g1_38 = f9_2 * (crypto_int64) g1_19;
+  crypto_int64 f9g2_19 = f9   * (crypto_int64) g2_19;
+  crypto_int64 f9g3_38 = f9_2 * (crypto_int64) g3_19;
+  crypto_int64 f9g4_19 = f9   * (crypto_int64) g4_19;
+  crypto_int64 f9g5_38 = f9_2 * (crypto_int64) g5_19;
+  crypto_int64 f9g6_19 = f9   * (crypto_int64) g6_19;
+  crypto_int64 f9g7_38 = f9_2 * (crypto_int64) g7_19;
+  crypto_int64 f9g8_19 = f9   * (crypto_int64) g8_19;
+  crypto_int64 f9g9_38 = f9_2 * (crypto_int64) g9_19;
+  crypto_int64 h0 = f0g0+f1g9_38+f2g8_19+f3g7_38+f4g6_19+f5g5_38+f6g4_19+f7g3_38+f8g2_19+f9g1_38;
+  crypto_int64 h1 = f0g1+f1g0   +f2g9_19+f3g8_19+f4g7_19+f5g6_19+f6g5_19+f7g4_19+f8g3_19+f9g2_19;
+  crypto_int64 h2 = f0g2+f1g1_2 +f2g0   +f3g9_38+f4g8_19+f5g7_38+f6g6_19+f7g5_38+f8g4_19+f9g3_38;
+  crypto_int64 h3 = f0g3+f1g2   +f2g1   +f3g0   +f4g9_19+f5g8_19+f6g7_19+f7g6_19+f8g5_19+f9g4_19;
+  crypto_int64 h4 = f0g4+f1g3_2 +f2g2   +f3g1_2 +f4g0   +f5g9_38+f6g8_19+f7g7_38+f8g6_19+f9g5_38;
+  crypto_int64 h5 = f0g5+f1g4   +f2g3   +f3g2   +f4g1   +f5g0   +f6g9_19+f7g8_19+f8g7_19+f9g6_19;
+  crypto_int64 h6 = f0g6+f1g5_2 +f2g4   +f3g3_2 +f4g2   +f5g1_2 +f6g0   +f7g9_38+f8g8_19+f9g7_38;
+  crypto_int64 h7 = f0g7+f1g6   +f2g5   +f3g4   +f4g3   +f5g2   +f6g1   +f7g0   +f8g9_19+f9g8_19;
+  crypto_int64 h8 = f0g8+f1g7_2 +f2g6   +f3g5_2 +f4g4   +f5g3_2 +f6g2   +f7g1_2 +f8g0   +f9g9_38;
+  crypto_int64 h9 = f0g9+f1g8   +f2g7   +f3g6   +f4g5   +f5g4   +f6g3   +f7g2   +f8g1   +f9g0   ;
+  crypto_int64 carry0;
+  crypto_int64 carry1;
+  crypto_int64 carry2;
+  crypto_int64 carry3;
+  crypto_int64 carry4;
+  crypto_int64 carry5;
+  crypto_int64 carry6;
+  crypto_int64 carry7;
+  crypto_int64 carry8;
+  crypto_int64 carry9;
+
+  /*
+  |h0| <= (1.65*1.65*2^52*(1+19+19+19+19)+1.65*1.65*2^50*(38+38+38+38+38))
+    i.e. |h0| <= 1.4*2^60; narrower ranges for h2, h4, h6, h8
+  |h1| <= (1.65*1.65*2^51*(1+1+19+19+19+19+19+19+19+19))
+    i.e. |h1| <= 1.7*2^59; narrower ranges for h3, h5, h7, h9
+  */
+
+  carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+  carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+  /* |h0| <= 2^25 */
+  /* |h4| <= 2^25 */
+  /* |h1| <= 1.71*2^59 */
+  /* |h5| <= 1.71*2^59 */
+
+  carry1 = (h1 + (crypto_int64) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+  carry5 = (h5 + (crypto_int64) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+  /* |h1| <= 2^24; from now on fits into int32 */
+  /* |h5| <= 2^24; from now on fits into int32 */
+  /* |h2| <= 1.41*2^60 */
+  /* |h6| <= 1.41*2^60 */
+
+  carry2 = (h2 + (crypto_int64) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+  carry6 = (h6 + (crypto_int64) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+  /* |h2| <= 2^25; from now on fits into int32 unchanged */
+  /* |h6| <= 2^25; from now on fits into int32 unchanged */
+  /* |h3| <= 1.71*2^59 */
+  /* |h7| <= 1.71*2^59 */
+
+  carry3 = (h3 + (crypto_int64) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+  carry7 = (h7 + (crypto_int64) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+  /* |h3| <= 2^24; from now on fits into int32 unchanged */
+  /* |h7| <= 2^24; from now on fits into int32 unchanged */
+  /* |h4| <= 1.72*2^34 */
+  /* |h8| <= 1.41*2^60 */
+
+  carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+  carry8 = (h8 + (crypto_int64) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+  /* |h4| <= 2^25; from now on fits into int32 unchanged */
+  /* |h8| <= 2^25; from now on fits into int32 unchanged */
+  /* |h5| <= 1.01*2^24 */
+  /* |h9| <= 1.71*2^59 */
+
+  carry9 = (h9 + (crypto_int64) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+  /* |h9| <= 2^24; from now on fits into int32 unchanged */
+  /* |h0| <= 1.1*2^39 */
+
+  carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+  /* |h0| <= 2^25; from now on fits into int32 unchanged */
+  /* |h1| <= 1.01*2^24 */
+
+  h[0] = h0;
+  h[1] = h1;
+  h[2] = h2;
+  h[3] = h3;
+  h[4] = h4;
+  h[5] = h5;
+  h[6] = h6;
+  h[7] = h7;
+  h[8] = h8;
+  h[9] = h9;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_neg.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_neg.c
new file mode 100644
index 0000000000..2078ce5284
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_neg.c
@@ -0,0 +1,45 @@
+#include "fe.h"
+
+/*
+h = -f
+
+Preconditions:
+   |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+
+Postconditions:
+   |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+*/
+
+void fe_neg(fe h,const fe f)
+{
+  crypto_int32 f0 = f[0];
+  crypto_int32 f1 = f[1];
+  crypto_int32 f2 = f[2];
+  crypto_int32 f3 = f[3];
+  crypto_int32 f4 = f[4];
+  crypto_int32 f5 = f[5];
+  crypto_int32 f6 = f[6];
+  crypto_int32 f7 = f[7];
+  crypto_int32 f8 = f[8];
+  crypto_int32 f9 = f[9];
+  crypto_int32 h0 = -f0;
+  crypto_int32 h1 = -f1;
+  crypto_int32 h2 = -f2;
+  crypto_int32 h3 = -f3;
+  crypto_int32 h4 = -f4;
+  crypto_int32 h5 = -f5;
+  crypto_int32 h6 = -f6;
+  crypto_int32 h7 = -f7;
+  crypto_int32 h8 = -f8;
+  crypto_int32 h9 = -f9;
+  h[0] = h0;
+  h[1] = h1;
+  h[2] = h2;
+  h[3] = h3;
+  h[4] = h4;
+  h[5] = h5;
+  h[6] = h6;
+  h[7] = h7;
+  h[8] = h8;
+  h[9] = h9;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_pow22523.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_pow22523.c
new file mode 100644
index 0000000000..56675a5902
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_pow22523.c
@@ -0,0 +1,13 @@
+#include "fe.h"
+
+void fe_pow22523(fe out,const fe z)
+{
+  fe t0;
+  fe t1;
+  fe t2;
+  int i;
+
+#include "pow22523.h"
+
+  return;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_sq.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_sq.c
new file mode 100644
index 0000000000..8dd119841c
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_sq.c
@@ -0,0 +1,149 @@
+#include "fe.h"
+#include "crypto_int64.h"
+
+/*
+h = f * f
+Can overlap h with f.
+
+Preconditions:
+   |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+
+Postconditions:
+   |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
+*/
+
+/*
+See fe_mul.c for discussion of implementation strategy.
+*/
+
+void fe_sq(fe h,const fe f)
+{
+  crypto_int32 f0 = f[0];
+  crypto_int32 f1 = f[1];
+  crypto_int32 f2 = f[2];
+  crypto_int32 f3 = f[3];
+  crypto_int32 f4 = f[4];
+  crypto_int32 f5 = f[5];
+  crypto_int32 f6 = f[6];
+  crypto_int32 f7 = f[7];
+  crypto_int32 f8 = f[8];
+  crypto_int32 f9 = f[9];
+  crypto_int32 f0_2 = 2 * f0;
+  crypto_int32 f1_2 = 2 * f1;
+  crypto_int32 f2_2 = 2 * f2;
+  crypto_int32 f3_2 = 2 * f3;
+  crypto_int32 f4_2 = 2 * f4;
+  crypto_int32 f5_2 = 2 * f5;
+  crypto_int32 f6_2 = 2 * f6;
+  crypto_int32 f7_2 = 2 * f7;
+  crypto_int32 f5_38 = 38 * f5; /* 1.959375*2^30 */
+  crypto_int32 f6_19 = 19 * f6; /* 1.959375*2^30 */
+  crypto_int32 f7_38 = 38 * f7; /* 1.959375*2^30 */
+  crypto_int32 f8_19 = 19 * f8; /* 1.959375*2^30 */
+  crypto_int32 f9_38 = 38 * f9; /* 1.959375*2^30 */
+  crypto_int64 f0f0    = f0   * (crypto_int64) f0;
+  crypto_int64 f0f1_2  = f0_2 * (crypto_int64) f1;
+  crypto_int64 f0f2_2  = f0_2 * (crypto_int64) f2;
+  crypto_int64 f0f3_2  = f0_2 * (crypto_int64) f3;
+  crypto_int64 f0f4_2  = f0_2 * (crypto_int64) f4;
+  crypto_int64 f0f5_2  = f0_2 * (crypto_int64) f5;
+  crypto_int64 f0f6_2  = f0_2 * (crypto_int64) f6;
+  crypto_int64 f0f7_2  = f0_2 * (crypto_int64) f7;
+  crypto_int64 f0f8_2  = f0_2 * (crypto_int64) f8;
+  crypto_int64 f0f9_2  = f0_2 * (crypto_int64) f9;
+  crypto_int64 f1f1_2  = f1_2 * (crypto_int64) f1;
+  crypto_int64 f1f2_2  = f1_2 * (crypto_int64) f2;
+  crypto_int64 f1f3_4  = f1_2 * (crypto_int64) f3_2;
+  crypto_int64 f1f4_2  = f1_2 * (crypto_int64) f4;
+  crypto_int64 f1f5_4  = f1_2 * (crypto_int64) f5_2;
+  crypto_int64 f1f6_2  = f1_2 * (crypto_int64) f6;
+  crypto_int64 f1f7_4  = f1_2 * (crypto_int64) f7_2;
+  crypto_int64 f1f8_2  = f1_2 * (crypto_int64) f8;
+  crypto_int64 f1f9_76 = f1_2 * (crypto_int64) f9_38;
+  crypto_int64 f2f2    = f2   * (crypto_int64) f2;
+  crypto_int64 f2f3_2  = f2_2 * (crypto_int64) f3;
+  crypto_int64 f2f4_2  = f2_2 * (crypto_int64) f4;
+  crypto_int64 f2f5_2  = f2_2 * (crypto_int64) f5;
+  crypto_int64 f2f6_2  = f2_2 * (crypto_int64) f6;
+  crypto_int64 f2f7_2  = f2_2 * (crypto_int64) f7;
+  crypto_int64 f2f8_38 = f2_2 * (crypto_int64) f8_19;
+  crypto_int64 f2f9_38 = f2   * (crypto_int64) f9_38;
+  crypto_int64 f3f3_2  = f3_2 * (crypto_int64) f3;
+  crypto_int64 f3f4_2  = f3_2 * (crypto_int64) f4;
+  crypto_int64 f3f5_4  = f3_2 * (crypto_int64) f5_2;
+  crypto_int64 f3f6_2  = f3_2 * (crypto_int64) f6;
+  crypto_int64 f3f7_76 = f3_2 * (crypto_int64) f7_38;
+  crypto_int64 f3f8_38 = f3_2 * (crypto_int64) f8_19;
+  crypto_int64 f3f9_76 = f3_2 * (crypto_int64) f9_38;
+  crypto_int64 f4f4    = f4   * (crypto_int64) f4;
+  crypto_int64 f4f5_2  = f4_2 * (crypto_int64) f5;
+  crypto_int64 f4f6_38 = f4_2 * (crypto_int64) f6_19;
+  crypto_int64 f4f7_38 = f4   * (crypto_int64) f7_38;
+  crypto_int64 f4f8_38 = f4_2 * (crypto_int64) f8_19;
+  crypto_int64 f4f9_38 = f4   * (crypto_int64) f9_38;
+  crypto_int64 f5f5_38 = f5   * (crypto_int64) f5_38;
+  crypto_int64 f5f6_38 = f5_2 * (crypto_int64) f6_19;
+  crypto_int64 f5f7_76 = f5_2 * (crypto_int64) f7_38;
+  crypto_int64 f5f8_38 = f5_2 * (crypto_int64) f8_19;
+  crypto_int64 f5f9_76 = f5_2 * (crypto_int64) f9_38;
+  crypto_int64 f6f6_19 = f6   * (crypto_int64) f6_19;
+  crypto_int64 f6f7_38 = f6   * (crypto_int64) f7_38;
+  crypto_int64 f6f8_38 = f6_2 * (crypto_int64) f8_19;
+  crypto_int64 f6f9_38 = f6   * (crypto_int64) f9_38;
+  crypto_int64 f7f7_38 = f7   * (crypto_int64) f7_38;
+  crypto_int64 f7f8_38 = f7_2 * (crypto_int64) f8_19;
+  crypto_int64 f7f9_76 = f7_2 * (crypto_int64) f9_38;
+  crypto_int64 f8f8_19 = f8   * (crypto_int64) f8_19;
+  crypto_int64 f8f9_38 = f8   * (crypto_int64) f9_38;
+  crypto_int64 f9f9_38 = f9   * (crypto_int64) f9_38;
+  crypto_int64 h0 = f0f0  +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38;
+  crypto_int64 h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38;
+  crypto_int64 h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19;
+  crypto_int64 h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38;
+  crypto_int64 h4 = f0f4_2+f1f3_4 +f2f2   +f5f9_76+f6f8_38+f7f7_38;
+  crypto_int64 h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38;
+  crypto_int64 h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19;
+  crypto_int64 h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38;
+  crypto_int64 h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4   +f9f9_38;
+  crypto_int64 h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2;
+  crypto_int64 carry0;
+  crypto_int64 carry1;
+  crypto_int64 carry2;
+  crypto_int64 carry3;
+  crypto_int64 carry4;
+  crypto_int64 carry5;
+  crypto_int64 carry6;
+  crypto_int64 carry7;
+  crypto_int64 carry8;
+  crypto_int64 carry9;
+
+  carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+  carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+
+  carry1 = (h1 + (crypto_int64) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+  carry5 = (h5 + (crypto_int64) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+
+  carry2 = (h2 + (crypto_int64) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+  carry6 = (h6 + (crypto_int64) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+
+  carry3 = (h3 + (crypto_int64) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+  carry7 = (h7 + (crypto_int64) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+  carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+  carry8 = (h8 + (crypto_int64) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+  carry9 = (h9 + (crypto_int64) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+
+  carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+
+  h[0] = h0;
+  h[1] = h1;
+  h[2] = h2;
+  h[3] = h3;
+  h[4] = h4;
+  h[5] = h5;
+  h[6] = h6;
+  h[7] = h7;
+  h[8] = h8;
+  h[9] = h9;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_sq2.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_sq2.c
new file mode 100644
index 0000000000..026ed3aacf
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_sq2.c
@@ -0,0 +1,160 @@
+#include "fe.h"
+#include "crypto_int64.h"
+
+/*
+h = 2 * f * f
+Can overlap h with f.
+
+Preconditions:
+   |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+
+Postconditions:
+   |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
+*/
+
+/*
+See fe_mul.c for discussion of implementation strategy.
+*/
+
+void fe_sq2(fe h,const fe f)
+{
+  crypto_int32 f0 = f[0];
+  crypto_int32 f1 = f[1];
+  crypto_int32 f2 = f[2];
+  crypto_int32 f3 = f[3];
+  crypto_int32 f4 = f[4];
+  crypto_int32 f5 = f[5];
+  crypto_int32 f6 = f[6];
+  crypto_int32 f7 = f[7];
+  crypto_int32 f8 = f[8];
+  crypto_int32 f9 = f[9];
+  crypto_int32 f0_2 = 2 * f0;
+  crypto_int32 f1_2 = 2 * f1;
+  crypto_int32 f2_2 = 2 * f2;
+  crypto_int32 f3_2 = 2 * f3;
+  crypto_int32 f4_2 = 2 * f4;
+  crypto_int32 f5_2 = 2 * f5;
+  crypto_int32 f6_2 = 2 * f6;
+  crypto_int32 f7_2 = 2 * f7;
+  crypto_int32 f5_38 = 38 * f5; /* 1.959375*2^30 */
+  crypto_int32 f6_19 = 19 * f6; /* 1.959375*2^30 */
+  crypto_int32 f7_38 = 38 * f7; /* 1.959375*2^30 */
+  crypto_int32 f8_19 = 19 * f8; /* 1.959375*2^30 */
+  crypto_int32 f9_38 = 38 * f9; /* 1.959375*2^30 */
+  crypto_int64 f0f0    = f0   * (crypto_int64) f0;
+  crypto_int64 f0f1_2  = f0_2 * (crypto_int64) f1;
+  crypto_int64 f0f2_2  = f0_2 * (crypto_int64) f2;
+  crypto_int64 f0f3_2  = f0_2 * (crypto_int64) f3;
+  crypto_int64 f0f4_2  = f0_2 * (crypto_int64) f4;
+  crypto_int64 f0f5_2  = f0_2 * (crypto_int64) f5;
+  crypto_int64 f0f6_2  = f0_2 * (crypto_int64) f6;
+  crypto_int64 f0f7_2  = f0_2 * (crypto_int64) f7;
+  crypto_int64 f0f8_2  = f0_2 * (crypto_int64) f8;
+  crypto_int64 f0f9_2  = f0_2 * (crypto_int64) f9;
+  crypto_int64 f1f1_2  = f1_2 * (crypto_int64) f1;
+  crypto_int64 f1f2_2  = f1_2 * (crypto_int64) f2;
+  crypto_int64 f1f3_4  = f1_2 * (crypto_int64) f3_2;
+  crypto_int64 f1f4_2  = f1_2 * (crypto_int64) f4;
+  crypto_int64 f1f5_4  = f1_2 * (crypto_int64) f5_2;
+  crypto_int64 f1f6_2  = f1_2 * (crypto_int64) f6;
+  crypto_int64 f1f7_4  = f1_2 * (crypto_int64) f7_2;
+  crypto_int64 f1f8_2  = f1_2 * (crypto_int64) f8;
+  crypto_int64 f1f9_76 = f1_2 * (crypto_int64) f9_38;
+  crypto_int64 f2f2    = f2   * (crypto_int64) f2;
+  crypto_int64 f2f3_2  = f2_2 * (crypto_int64) f3;
+  crypto_int64 f2f4_2  = f2_2 * (crypto_int64) f4;
+  crypto_int64 f2f5_2  = f2_2 * (crypto_int64) f5;
+  crypto_int64 f2f6_2  = f2_2 * (crypto_int64) f6;
+  crypto_int64 f2f7_2  = f2_2 * (crypto_int64) f7;
+  crypto_int64 f2f8_38 = f2_2 * (crypto_int64) f8_19;
+  crypto_int64 f2f9_38 = f2   * (crypto_int64) f9_38;
+  crypto_int64 f3f3_2  = f3_2 * (crypto_int64) f3;
+  crypto_int64 f3f4_2  = f3_2 * (crypto_int64) f4;
+  crypto_int64 f3f5_4  = f3_2 * (crypto_int64) f5_2;
+  crypto_int64 f3f6_2  = f3_2 * (crypto_int64) f6;
+  crypto_int64 f3f7_76 = f3_2 * (crypto_int64) f7_38;
+  crypto_int64 f3f8_38 = f3_2 * (crypto_int64) f8_19;
+  crypto_int64 f3f9_76 = f3_2 * (crypto_int64) f9_38;
+  crypto_int64 f4f4    = f4   * (crypto_int64) f4;
+  crypto_int64 f4f5_2  = f4_2 * (crypto_int64) f5;
+  crypto_int64 f4f6_38 = f4_2 * (crypto_int64) f6_19;
+  crypto_int64 f4f7_38 = f4   * (crypto_int64) f7_38;
+  crypto_int64 f4f8_38 = f4_2 * (crypto_int64) f8_19;
+  crypto_int64 f4f9_38 = f4   * (crypto_int64) f9_38;
+  crypto_int64 f5f5_38 = f5   * (crypto_int64) f5_38;
+  crypto_int64 f5f6_38 = f5_2 * (crypto_int64) f6_19;
+  crypto_int64 f5f7_76 = f5_2 * (crypto_int64) f7_38;
+  crypto_int64 f5f8_38 = f5_2 * (crypto_int64) f8_19;
+  crypto_int64 f5f9_76 = f5_2 * (crypto_int64) f9_38;
+  crypto_int64 f6f6_19 = f6   * (crypto_int64) f6_19;
+  crypto_int64 f6f7_38 = f6   * (crypto_int64) f7_38;
+  crypto_int64 f6f8_38 = f6_2 * (crypto_int64) f8_19;
+  crypto_int64 f6f9_38 = f6   * (crypto_int64) f9_38;
+  crypto_int64 f7f7_38 = f7   * (crypto_int64) f7_38;
+  crypto_int64 f7f8_38 = f7_2 * (crypto_int64) f8_19;
+  crypto_int64 f7f9_76 = f7_2 * (crypto_int64) f9_38;
+  crypto_int64 f8f8_19 = f8   * (crypto_int64) f8_19;
+  crypto_int64 f8f9_38 = f8   * (crypto_int64) f9_38;
+  crypto_int64 f9f9_38 = f9   * (crypto_int64) f9_38;
+  crypto_int64 h0 = f0f0  +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38;
+  crypto_int64 h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38;
+  crypto_int64 h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19;
+  crypto_int64 h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38;
+  crypto_int64 h4 = f0f4_2+f1f3_4 +f2f2   +f5f9_76+f6f8_38+f7f7_38;
+  crypto_int64 h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38;
+  crypto_int64 h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19;
+  crypto_int64 h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38;
+  crypto_int64 h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4   +f9f9_38;
+  crypto_int64 h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2;
+  crypto_int64 carry0;
+  crypto_int64 carry1;
+  crypto_int64 carry2;
+  crypto_int64 carry3;
+  crypto_int64 carry4;
+  crypto_int64 carry5;
+  crypto_int64 carry6;
+  crypto_int64 carry7;
+  crypto_int64 carry8;
+  crypto_int64 carry9;
+
+  h0 += h0;
+  h1 += h1;
+  h2 += h2;
+  h3 += h3;
+  h4 += h4;
+  h5 += h5;
+  h6 += h6;
+  h7 += h7;
+  h8 += h8;
+  h9 += h9;
+
+  carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+  carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+
+  carry1 = (h1 + (crypto_int64) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+  carry5 = (h5 + (crypto_int64) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+
+  carry2 = (h2 + (crypto_int64) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+  carry6 = (h6 + (crypto_int64) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+
+  carry3 = (h3 + (crypto_int64) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+  carry7 = (h7 + (crypto_int64) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+  carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+  carry8 = (h8 + (crypto_int64) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+  carry9 = (h9 + (crypto_int64) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+
+  carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+
+  h[0] = h0;
+  h[1] = h1;
+  h[2] = h2;
+  h[3] = h3;
+  h[4] = h4;
+  h[5] = h5;
+  h[6] = h6;
+  h[7] = h7;
+  h[8] = h8;
+  h[9] = h9;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_sub.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_sub.c
new file mode 100644
index 0000000000..6e26b7df8f
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_sub.c
@@ -0,0 +1,57 @@
+#include "fe.h"
+
+/*
+h = f - g
+Can overlap h with f or g.
+
+Preconditions:
+   |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+   |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+
+Postconditions:
+   |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+void fe_sub(fe h,const fe f,const fe g)
+{
+  crypto_int32 f0 = f[0];
+  crypto_int32 f1 = f[1];
+  crypto_int32 f2 = f[2];
+  crypto_int32 f3 = f[3];
+  crypto_int32 f4 = f[4];
+  crypto_int32 f5 = f[5];
+  crypto_int32 f6 = f[6];
+  crypto_int32 f7 = f[7];
+  crypto_int32 f8 = f[8];
+  crypto_int32 f9 = f[9];
+  crypto_int32 g0 = g[0];
+  crypto_int32 g1 = g[1];
+  crypto_int32 g2 = g[2];
+  crypto_int32 g3 = g[3];
+  crypto_int32 g4 = g[4];
+  crypto_int32 g5 = g[5];
+  crypto_int32 g6 = g[6];
+  crypto_int32 g7 = g[7];
+  crypto_int32 g8 = g[8];
+  crypto_int32 g9 = g[9];
+  crypto_int32 h0 = f0 - g0;
+  crypto_int32 h1 = f1 - g1;
+  crypto_int32 h2 = f2 - g2;
+  crypto_int32 h3 = f3 - g3;
+  crypto_int32 h4 = f4 - g4;
+  crypto_int32 h5 = f5 - g5;
+  crypto_int32 h6 = f6 - g6;
+  crypto_int32 h7 = f7 - g7;
+  crypto_int32 h8 = f8 - g8;
+  crypto_int32 h9 = f9 - g9;
+  h[0] = h0;
+  h[1] = h1;
+  h[2] = h2;
+  h[3] = h3;
+  h[4] = h4;
+  h[5] = h5;
+  h[6] = h6;
+  h[7] = h7;
+  h[8] = h8;
+  h[9] = h9;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_tobytes.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_tobytes.c
new file mode 100644
index 0000000000..0a63baf9c1
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_tobytes.c
@@ -0,0 +1,119 @@
+#include "fe.h"
+
+/*
+Preconditions:
+  |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+
+Write p=2^255-19; q=floor(h/p).
+Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))).
+
+Proof:
+  Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4.
+  Also have |h-2^230 h9|<2^231 so |19 2^(-255)(h-2^230 h9)|<1/4.
+
+  Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9).
+  Then 0<y<1.
+
+  Write r=h-pq.
+  Have 0<=r<=p-1=2^255-20.
+  Thus 0<=r+19(2^-255)r<r+19(2^-255)2^255<=2^255-1.
+
+  Write x=r+19(2^-255)r+y.
+  Then 0<x<2^255 so floor(2^(-255)x) = 0 so floor(q+2^(-255)x) = q.
+
+  Have q+2^(-255)x = 2^(-255)(h + 19 2^(-25) h9 + 2^(-1))
+  so floor(2^(-255)(h + 19 2^(-25) h9 + 2^(-1))) = q.
+*/
+
+void fe_tobytes(unsigned char *s,const fe h)
+{
+  crypto_int32 h0 = h[0];
+  crypto_int32 h1 = h[1];
+  crypto_int32 h2 = h[2];
+  crypto_int32 h3 = h[3];
+  crypto_int32 h4 = h[4];
+  crypto_int32 h5 = h[5];
+  crypto_int32 h6 = h[6];
+  crypto_int32 h7 = h[7];
+  crypto_int32 h8 = h[8];
+  crypto_int32 h9 = h[9];
+  crypto_int32 q;
+  crypto_int32 carry0;
+  crypto_int32 carry1;
+  crypto_int32 carry2;
+  crypto_int32 carry3;
+  crypto_int32 carry4;
+  crypto_int32 carry5;
+  crypto_int32 carry6;
+  crypto_int32 carry7;
+  crypto_int32 carry8;
+  crypto_int32 carry9;
+
+  q = (19 * h9 + (((crypto_int32) 1) << 24)) >> 25;
+  q = (h0 + q) >> 26;
+  q = (h1 + q) >> 25;
+  q = (h2 + q) >> 26;
+  q = (h3 + q) >> 25;
+  q = (h4 + q) >> 26;
+  q = (h5 + q) >> 25;
+  q = (h6 + q) >> 26;
+  q = (h7 + q) >> 25;
+  q = (h8 + q) >> 26;
+  q = (h9 + q) >> 25;
+
+  /* Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. */
+  h0 += 19 * q;
+  /* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */
+
+  carry0 = h0 >> 26; h1 += carry0; h0 -= carry0 << 26;
+  carry1 = h1 >> 25; h2 += carry1; h1 -= carry1 << 25;
+  carry2 = h2 >> 26; h3 += carry2; h2 -= carry2 << 26;
+  carry3 = h3 >> 25; h4 += carry3; h3 -= carry3 << 25;
+  carry4 = h4 >> 26; h5 += carry4; h4 -= carry4 << 26;
+  carry5 = h5 >> 25; h6 += carry5; h5 -= carry5 << 25;
+  carry6 = h6 >> 26; h7 += carry6; h6 -= carry6 << 26;
+  carry7 = h7 >> 25; h8 += carry7; h7 -= carry7 << 25;
+  carry8 = h8 >> 26; h9 += carry8; h8 -= carry8 << 26;
+  carry9 = h9 >> 25;               h9 -= carry9 << 25;
+                  /* h10 = carry9 */
+
+  /*
+  Goal: Output h0+...+2^255 h10-2^255 q, which is between 0 and 2^255-20.
+  Have h0+...+2^230 h9 between 0 and 2^255-1;
+  evidently 2^255 h10-2^255 q = 0.
+  Goal: Output h0+...+2^230 h9.
+  */
+
+  s[0] = h0 >> 0;
+  s[1] = h0 >> 8;
+  s[2] = h0 >> 16;
+  s[3] = (h0 >> 24) | (h1 << 2);
+  s[4] = h1 >> 6;
+  s[5] = h1 >> 14;
+  s[6] = (h1 >> 22) | (h2 << 3);
+  s[7] = h2 >> 5;
+  s[8] = h2 >> 13;
+  s[9] = (h2 >> 21) | (h3 << 5);
+  s[10] = h3 >> 3;
+  s[11] = h3 >> 11;
+  s[12] = (h3 >> 19) | (h4 << 6);
+  s[13] = h4 >> 2;
+  s[14] = h4 >> 10;
+  s[15] = h4 >> 18;
+  s[16] = h5 >> 0;
+  s[17] = h5 >> 8;
+  s[18] = h5 >> 16;
+  s[19] = (h5 >> 24) | (h6 << 1);
+  s[20] = h6 >> 7;
+  s[21] = h6 >> 15;
+  s[22] = (h6 >> 23) | (h7 << 3);
+  s[23] = h7 >> 5;
+  s[24] = h7 >> 13;
+  s[25] = (h7 >> 21) | (h8 << 4);
+  s[26] = h8 >> 4;
+  s[27] = h8 >> 12;
+  s[28] = (h8 >> 20) | (h9 << 6);
+  s[29] = h9 >> 2;
+  s[30] = h9 >> 10;
+  s[31] = h9 >> 18;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge.h b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge.h
new file mode 100644
index 0000000000..55e95f95b6
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge.h
@@ -0,0 +1,95 @@
+#ifndef GE_H
+#define GE_H
+
+/*
+ge means group element.
+
+Here the group is the set of pairs (x,y) of field elements (see fe.h)
+satisfying -x^2 + y^2 = 1 + d x^2y^2
+where d = -121665/121666.
+
+Representations:
+  ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z
+  ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT
+  ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T
+  ge_precomp (Duif): (y+x,y-x,2dxy)
+*/
+
+#include "fe.h"
+
+typedef struct {
+  fe X;
+  fe Y;
+  fe Z;
+} ge_p2;
+
+typedef struct {
+  fe X;
+  fe Y;
+  fe Z;
+  fe T;
+} ge_p3;
+
+typedef struct {
+  fe X;
+  fe Y;
+  fe Z;
+  fe T;
+} ge_p1p1;
+
+typedef struct {
+  fe yplusx;
+  fe yminusx;
+  fe xy2d;
+} ge_precomp;
+
+typedef struct {
+  fe YplusX;
+  fe YminusX;
+  fe Z;
+  fe T2d;
+} ge_cached;
+
+#define ge_frombytes_negate_vartime crypto_sign_ed25519_ref10_ge_frombytes_negate_vartime
+#define ge_tobytes crypto_sign_ed25519_ref10_ge_tobytes
+#define ge_p3_tobytes crypto_sign_ed25519_ref10_ge_p3_tobytes
+
+#define ge_p2_0 crypto_sign_ed25519_ref10_ge_p2_0
+#define ge_p3_0 crypto_sign_ed25519_ref10_ge_p3_0
+#define ge_precomp_0 crypto_sign_ed25519_ref10_ge_precomp_0
+#define ge_p3_to_p2 crypto_sign_ed25519_ref10_ge_p3_to_p2
+#define ge_p3_to_cached crypto_sign_ed25519_ref10_ge_p3_to_cached
+#define ge_p1p1_to_p2 crypto_sign_ed25519_ref10_ge_p1p1_to_p2
+#define ge_p1p1_to_p3 crypto_sign_ed25519_ref10_ge_p1p1_to_p3
+#define ge_p2_dbl crypto_sign_ed25519_ref10_ge_p2_dbl
+#define ge_p3_dbl crypto_sign_ed25519_ref10_ge_p3_dbl
+
+#define ge_madd crypto_sign_ed25519_ref10_ge_madd
+#define ge_msub crypto_sign_ed25519_ref10_ge_msub
+#define ge_add crypto_sign_ed25519_ref10_ge_add
+#define ge_sub crypto_sign_ed25519_ref10_ge_sub
+#define ge_scalarmult_base crypto_sign_ed25519_ref10_ge_scalarmult_base
+#define ge_double_scalarmult_vartime crypto_sign_ed25519_ref10_ge_double_scalarmult_vartime
+
+extern void ge_tobytes(unsigned char *,const ge_p2 *);
+extern void ge_p3_tobytes(unsigned char *,const ge_p3 *);
+extern int ge_frombytes_negate_vartime(ge_p3 *,const unsigned char *);
+
+extern void ge_p2_0(ge_p2 *);
+extern void ge_p3_0(ge_p3 *);
+extern void ge_precomp_0(ge_precomp *);
+extern void ge_p3_to_p2(ge_p2 *,const ge_p3 *);
+extern void ge_p3_to_cached(ge_cached *,const ge_p3 *);
+extern void ge_p1p1_to_p2(ge_p2 *,const ge_p1p1 *);
+extern void ge_p1p1_to_p3(ge_p3 *,const ge_p1p1 *);
+extern void ge_p2_dbl(ge_p1p1 *,const ge_p2 *);
+extern void ge_p3_dbl(ge_p1p1 *,const ge_p3 *);
+
+extern void ge_madd(ge_p1p1 *,const ge_p3 *,const ge_precomp *);
+extern void ge_msub(ge_p1p1 *,const ge_p3 *,const ge_precomp *);
+extern void ge_add(ge_p1p1 *,const ge_p3 *,const ge_cached *);
+extern void ge_sub(ge_p1p1 *,const ge_p3 *,const ge_cached *);
+extern void ge_scalarmult_base(ge_p3 *,const unsigned char *);
+extern void ge_double_scalarmult_vartime(ge_p2 *,const unsigned char *,const ge_p3 *,const unsigned char *);
+
+#endif
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_add.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_add.c
new file mode 100644
index 0000000000..da7ff5d2eb
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_add.c
@@ -0,0 +1,11 @@
+#include "ge.h"
+
+/*
+r = p + q
+*/
+
+void ge_add(ge_p1p1 *r,const ge_p3 *p,const ge_cached *q)
+{
+  fe t0;
+#include "ge_add.h"
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_add.h b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_add.h
new file mode 100644
index 0000000000..7481f8ffbe
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_add.h
@@ -0,0 +1,97 @@
+
+/* qhasm: enter ge_add */
+
+/* qhasm: fe X1 */
+
+/* qhasm: fe Y1 */
+
+/* qhasm: fe Z1 */
+
+/* qhasm: fe Z2 */
+
+/* qhasm: fe T1 */
+
+/* qhasm: fe ZZ */
+
+/* qhasm: fe YpX2 */
+
+/* qhasm: fe YmX2 */
+
+/* qhasm: fe T2d2 */
+
+/* qhasm: fe X3 */
+
+/* qhasm: fe Y3 */
+
+/* qhasm: fe Z3 */
+
+/* qhasm: fe T3 */
+
+/* qhasm: fe YpX1 */
+
+/* qhasm: fe YmX1 */
+
+/* qhasm: fe A */
+
+/* qhasm: fe B */
+
+/* qhasm: fe C */
+
+/* qhasm: fe D */
+
+/* qhasm: YpX1 = Y1+X1 */
+/* asm 1: fe_add(>YpX1=fe#1,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_add(>YpX1=r->X,<Y1=p->Y,<X1=p->X); */
+fe_add(r->X,p->Y,p->X);
+
+/* qhasm: YmX1 = Y1-X1 */
+/* asm 1: fe_sub(>YmX1=fe#2,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_sub(>YmX1=r->Y,<Y1=p->Y,<X1=p->X); */
+fe_sub(r->Y,p->Y,p->X);
+
+/* qhasm: A = YpX1*YpX2 */
+/* asm 1: fe_mul(>A=fe#3,<YpX1=fe#1,<YpX2=fe#15); */
+/* asm 2: fe_mul(>A=r->Z,<YpX1=r->X,<YpX2=q->YplusX); */
+fe_mul(r->Z,r->X,q->YplusX);
+
+/* qhasm: B = YmX1*YmX2 */
+/* asm 1: fe_mul(>B=fe#2,<YmX1=fe#2,<YmX2=fe#16); */
+/* asm 2: fe_mul(>B=r->Y,<YmX1=r->Y,<YmX2=q->YminusX); */
+fe_mul(r->Y,r->Y,q->YminusX);
+
+/* qhasm: C = T2d2*T1 */
+/* asm 1: fe_mul(>C=fe#4,<T2d2=fe#18,<T1=fe#14); */
+/* asm 2: fe_mul(>C=r->T,<T2d2=q->T2d,<T1=p->T); */
+fe_mul(r->T,q->T2d,p->T);
+
+/* qhasm: ZZ = Z1*Z2 */
+/* asm 1: fe_mul(>ZZ=fe#1,<Z1=fe#13,<Z2=fe#17); */
+/* asm 2: fe_mul(>ZZ=r->X,<Z1=p->Z,<Z2=q->Z); */
+fe_mul(r->X,p->Z,q->Z);
+
+/* qhasm: D = 2*ZZ */
+/* asm 1: fe_add(>D=fe#5,<ZZ=fe#1,<ZZ=fe#1); */
+/* asm 2: fe_add(>D=t0,<ZZ=r->X,<ZZ=r->X); */
+fe_add(t0,r->X,r->X);
+
+/* qhasm: X3 = A-B */
+/* asm 1: fe_sub(>X3=fe#1,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_sub(>X3=r->X,<A=r->Z,<B=r->Y); */
+fe_sub(r->X,r->Z,r->Y);
+
+/* qhasm: Y3 = A+B */
+/* asm 1: fe_add(>Y3=fe#2,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_add(>Y3=r->Y,<A=r->Z,<B=r->Y); */
+fe_add(r->Y,r->Z,r->Y);
+
+/* qhasm: Z3 = D+C */
+/* asm 1: fe_add(>Z3=fe#3,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_add(>Z3=r->Z,<D=t0,<C=r->T); */
+fe_add(r->Z,t0,r->T);
+
+/* qhasm: T3 = D-C */
+/* asm 1: fe_sub(>T3=fe#4,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_sub(>T3=r->T,<D=t0,<C=r->T); */
+fe_sub(r->T,t0,r->T);
+
+/* qhasm: return */
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_add.q b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_add.q
new file mode 100644
index 0000000000..a6572ab0f8
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_add.q
@@ -0,0 +1,49 @@
+:name:fe:r->X:r->Y:r->Z:r->T:t0:t1:t2:t3:t4:t5:p->X:p->Y:p->Z:p->T:q->YplusX:q->YminusX:q->Z:q->T2d:
+fe r:var/r=fe:
+
+enter f:enter/f:>X1=fe#11:>Y1=fe#12:>Z1=fe#13:>T1=fe#14:>YpX2=fe#15:>YmX2=fe#16:>Z2=fe#17:>T2d2=fe#18:
+return:nofallthrough:<X3=fe#1:<Y3=fe#2:<Z3=fe#3:<T3=fe#4:leave:
+
+h=f+g:<f=fe:<g=fe:>h=fe:asm/fe_add(>h,<f,<g);:
+h=f-g:<f=fe:<g=fe:>h=fe:asm/fe_sub(>h,<f,<g);:
+h=f*g:<f=fe:<g=fe:>h=fe:asm/fe_mul(>h,<f,<g);:
+h=f^2:<f=fe:>h=fe:asm/fe_sq(>h,<f);:
+h=2*g:<g=fe:>h=fe:asm/fe_add(>h,<g,<g);:
+
+:
+
+enter ge_add
+
+fe X1
+fe Y1
+fe Z1
+fe Z2
+fe T1
+fe ZZ
+fe YpX2
+fe YmX2
+fe T2d2
+fe X3
+fe Y3
+fe Z3
+fe T3
+fe YpX1
+fe YmX1
+fe A
+fe B
+fe C
+fe D
+
+YpX1 = Y1+X1
+YmX1 = Y1-X1
+A = YpX1*YpX2
+B = YmX1*YmX2
+C = T2d2*T1
+ZZ = Z1*Z2
+D = 2*ZZ
+X3 = A-B
+Y3 = A+B
+Z3 = D+C
+T3 = D-C
+
+return
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_double_scalarmult.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_double_scalarmult.c
new file mode 100644
index 0000000000..f8bf4bf775
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_double_scalarmult.c
@@ -0,0 +1,96 @@
+#include "ge.h"
+
+static void slide(signed char *r,const unsigned char *a)
+{
+  int i;
+  int b;
+  int k;
+
+  for (i = 0;i < 256;++i)
+    r[i] = 1 & (a[i >> 3] >> (i & 7));
+
+  for (i = 0;i < 256;++i)
+    if (r[i]) {
+      for (b = 1;b <= 6 && i + b < 256;++b) {
+        if (r[i + b]) {
+          if (r[i] + (r[i + b] << b) <= 15) {
+            r[i] += r[i + b] << b; r[i + b] = 0;
+          } else if (r[i] - (r[i + b] << b) >= -15) {
+            r[i] -= r[i + b] << b;
+            for (k = i + b;k < 256;++k) {
+              if (!r[k]) {
+                r[k] = 1;
+                break;
+              }
+              r[k] = 0;
+            }
+          } else
+            break;
+        }
+      }
+    }
+
+}
+
+static ge_precomp Bi[8] = {
+#include "base2.h"
+} ;
+
+/*
+r = a * A + b * B
+where a = a[0]+256*a[1]+...+256^31 a[31].
+and b = b[0]+256*b[1]+...+256^31 b[31].
+B is the Ed25519 base point (x,4/5) with x positive.
+*/
+
+void ge_double_scalarmult_vartime(ge_p2 *r,const unsigned char *a,const ge_p3 *A,const unsigned char *b)
+{
+  signed char aslide[256];
+  signed char bslide[256];
+  ge_cached Ai[8]; /* A,3A,5A,7A,9A,11A,13A,15A */
+  ge_p1p1 t;
+  ge_p3 u;
+  ge_p3 A2;
+  int i;
+
+  slide(aslide,a);
+  slide(bslide,b);
+
+  ge_p3_to_cached(&Ai[0],A);
+  ge_p3_dbl(&t,A); ge_p1p1_to_p3(&A2,&t);
+  ge_add(&t,&A2,&Ai[0]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[1],&u);
+  ge_add(&t,&A2,&Ai[1]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[2],&u);
+  ge_add(&t,&A2,&Ai[2]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[3],&u);
+  ge_add(&t,&A2,&Ai[3]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[4],&u);
+  ge_add(&t,&A2,&Ai[4]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[5],&u);
+  ge_add(&t,&A2,&Ai[5]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[6],&u);
+  ge_add(&t,&A2,&Ai[6]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[7],&u);
+
+  ge_p2_0(r);
+
+  for (i = 255;i >= 0;--i) {
+    if (aslide[i] || bslide[i]) break;
+  }
+
+  for (;i >= 0;--i) {
+    ge_p2_dbl(&t,r);
+
+    if (aslide[i] > 0) {
+      ge_p1p1_to_p3(&u,&t);
+      ge_add(&t,&u,&Ai[aslide[i]/2]);
+    } else if (aslide[i] < 0) {
+      ge_p1p1_to_p3(&u,&t);
+      ge_sub(&t,&u,&Ai[(-aslide[i])/2]);
+    }
+
+    if (bslide[i] > 0) {
+      ge_p1p1_to_p3(&u,&t);
+      ge_madd(&t,&u,&Bi[bslide[i]/2]);
+    } else if (bslide[i] < 0) {
+      ge_p1p1_to_p3(&u,&t);
+      ge_msub(&t,&u,&Bi[(-bslide[i])/2]);
+    }
+
+    ge_p1p1_to_p2(r,&t);
+  }
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_frombytes.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_frombytes.c
new file mode 100644
index 0000000000..1a059ee93f
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_frombytes.c
@@ -0,0 +1,50 @@
+#include "ge.h"
+
+static const fe d = {
+#include "d.h"
+} ;
+
+static const fe sqrtm1 = {
+#include "sqrtm1.h"
+} ;
+
+int ge_frombytes_negate_vartime(ge_p3 *h,const unsigned char *s)
+{
+  fe u;
+  fe v;
+  fe v3;
+  fe vxx;
+  fe check;
+
+  fe_frombytes(h->Y,s);
+  fe_1(h->Z);
+  fe_sq(u,h->Y);
+  fe_mul(v,u,d);
+  fe_sub(u,u,h->Z);       /* u = y^2-1 */
+  fe_add(v,v,h->Z);       /* v = dy^2+1 */
+
+  fe_sq(v3,v);
+  fe_mul(v3,v3,v);        /* v3 = v^3 */
+  fe_sq(h->X,v3);
+  fe_mul(h->X,h->X,v);
+  fe_mul(h->X,h->X,u);    /* x = uv^7 */
+
+  fe_pow22523(h->X,h->X); /* x = (uv^7)^((q-5)/8) */
+  fe_mul(h->X,h->X,v3);
+  fe_mul(h->X,h->X,u);    /* x = uv^3(uv^7)^((q-5)/8) */
+
+  fe_sq(vxx,h->X);
+  fe_mul(vxx,vxx,v);
+  fe_sub(check,vxx,u);    /* vx^2-u */
+  if (fe_isnonzero(check)) {
+    fe_add(check,vxx,u);  /* vx^2+u */
+    if (fe_isnonzero(check)) return -1;
+    fe_mul(h->X,h->X,sqrtm1);
+  }
+
+  if (fe_isnegative(h->X) == (s[31] >> 7))
+    fe_neg(h->X,h->X);
+
+  fe_mul(h->T,h->X,h->Y);
+  return 0;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_madd.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_madd.c
new file mode 100644
index 0000000000..622571774b
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_madd.c
@@ -0,0 +1,11 @@
+#include "ge.h"
+
+/*
+r = p + q
+*/
+
+void ge_madd(ge_p1p1 *r,const ge_p3 *p,const ge_precomp *q)
+{
+  fe t0;
+#include "ge_madd.h"
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_madd.h b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_madd.h
new file mode 100644
index 0000000000..ecae84952b
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_madd.h
@@ -0,0 +1,88 @@
+
+/* qhasm: enter ge_madd */
+
+/* qhasm: fe X1 */
+
+/* qhasm: fe Y1 */
+
+/* qhasm: fe Z1 */
+
+/* qhasm: fe T1 */
+
+/* qhasm: fe ypx2 */
+
+/* qhasm: fe ymx2 */
+
+/* qhasm: fe xy2d2 */
+
+/* qhasm: fe X3 */
+
+/* qhasm: fe Y3 */
+
+/* qhasm: fe Z3 */
+
+/* qhasm: fe T3 */
+
+/* qhasm: fe YpX1 */
+
+/* qhasm: fe YmX1 */
+
+/* qhasm: fe A */
+
+/* qhasm: fe B */
+
+/* qhasm: fe C */
+
+/* qhasm: fe D */
+
+/* qhasm: YpX1 = Y1+X1 */
+/* asm 1: fe_add(>YpX1=fe#1,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_add(>YpX1=r->X,<Y1=p->Y,<X1=p->X); */
+fe_add(r->X,p->Y,p->X);
+
+/* qhasm: YmX1 = Y1-X1 */
+/* asm 1: fe_sub(>YmX1=fe#2,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_sub(>YmX1=r->Y,<Y1=p->Y,<X1=p->X); */
+fe_sub(r->Y,p->Y,p->X);
+
+/* qhasm: A = YpX1*ypx2 */
+/* asm 1: fe_mul(>A=fe#3,<YpX1=fe#1,<ypx2=fe#15); */
+/* asm 2: fe_mul(>A=r->Z,<YpX1=r->X,<ypx2=q->yplusx); */
+fe_mul(r->Z,r->X,q->yplusx);
+
+/* qhasm: B = YmX1*ymx2 */
+/* asm 1: fe_mul(>B=fe#2,<YmX1=fe#2,<ymx2=fe#16); */
+/* asm 2: fe_mul(>B=r->Y,<YmX1=r->Y,<ymx2=q->yminusx); */
+fe_mul(r->Y,r->Y,q->yminusx);
+
+/* qhasm: C = xy2d2*T1 */
+/* asm 1: fe_mul(>C=fe#4,<xy2d2=fe#17,<T1=fe#14); */
+/* asm 2: fe_mul(>C=r->T,<xy2d2=q->xy2d,<T1=p->T); */
+fe_mul(r->T,q->xy2d,p->T);
+
+/* qhasm: D = 2*Z1 */
+/* asm 1: fe_add(>D=fe#5,<Z1=fe#13,<Z1=fe#13); */
+/* asm 2: fe_add(>D=t0,<Z1=p->Z,<Z1=p->Z); */
+fe_add(t0,p->Z,p->Z);
+
+/* qhasm: X3 = A-B */
+/* asm 1: fe_sub(>X3=fe#1,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_sub(>X3=r->X,<A=r->Z,<B=r->Y); */
+fe_sub(r->X,r->Z,r->Y);
+
+/* qhasm: Y3 = A+B */
+/* asm 1: fe_add(>Y3=fe#2,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_add(>Y3=r->Y,<A=r->Z,<B=r->Y); */
+fe_add(r->Y,r->Z,r->Y);
+
+/* qhasm: Z3 = D+C */
+/* asm 1: fe_add(>Z3=fe#3,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_add(>Z3=r->Z,<D=t0,<C=r->T); */
+fe_add(r->Z,t0,r->T);
+
+/* qhasm: T3 = D-C */
+/* asm 1: fe_sub(>T3=fe#4,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_sub(>T3=r->T,<D=t0,<C=r->T); */
+fe_sub(r->T,t0,r->T);
+
+/* qhasm: return */
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_madd.q b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_madd.q
new file mode 100644
index 0000000000..aa3db454e6
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_madd.q
@@ -0,0 +1,46 @@
+:name:fe:r->X:r->Y:r->Z:r->T:t0:t1:t2:t3:t4:t5:p->X:p->Y:p->Z:p->T:q->yplusx:q->yminusx:q->xy2d:
+fe r:var/r=fe:
+
+enter f:enter/f:>X1=fe#11:>Y1=fe#12:>Z1=fe#13:>T1=fe#14:>ypx2=fe#15:>ymx2=fe#16:>xy2d2=fe#17:
+return:nofallthrough:<X3=fe#1:<Y3=fe#2:<Z3=fe#3:<T3=fe#4:leave:
+
+h=f+g:<f=fe:<g=fe:>h=fe:asm/fe_add(>h,<f,<g);:
+h=f-g:<f=fe:<g=fe:>h=fe:asm/fe_sub(>h,<f,<g);:
+h=f*g:<f=fe:<g=fe:>h=fe:asm/fe_mul(>h,<f,<g);:
+h=f^2:<f=fe:>h=fe:asm/fe_sq(>h,<f);:
+h=2*g:<g=fe:>h=fe:asm/fe_add(>h,<g,<g);:
+
+:
+
+enter ge_madd
+
+fe X1
+fe Y1
+fe Z1
+fe T1
+fe ypx2
+fe ymx2
+fe xy2d2
+fe X3
+fe Y3
+fe Z3
+fe T3
+fe YpX1
+fe YmX1
+fe A
+fe B
+fe C
+fe D
+
+YpX1 = Y1+X1
+YmX1 = Y1-X1
+A = YpX1*ypx2
+B = YmX1*ymx2
+C = xy2d2*T1
+D = 2*Z1
+X3 = A-B
+Y3 = A+B
+Z3 = D+C
+T3 = D-C
+
+return
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_msub.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_msub.c
new file mode 100644
index 0000000000..741ecbf113
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_msub.c
@@ -0,0 +1,11 @@
+#include "ge.h"
+
+/*
+r = p - q
+*/
+
+void ge_msub(ge_p1p1 *r,const ge_p3 *p,const ge_precomp *q)
+{
+  fe t0;
+#include "ge_msub.h"
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_msub.h b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_msub.h
new file mode 100644
index 0000000000..500f986ba0
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_msub.h
@@ -0,0 +1,88 @@
+
+/* qhasm: enter ge_msub */
+
+/* qhasm: fe X1 */
+
+/* qhasm: fe Y1 */
+
+/* qhasm: fe Z1 */
+
+/* qhasm: fe T1 */
+
+/* qhasm: fe ypx2 */
+
+/* qhasm: fe ymx2 */
+
+/* qhasm: fe xy2d2 */
+
+/* qhasm: fe X3 */
+
+/* qhasm: fe Y3 */
+
+/* qhasm: fe Z3 */
+
+/* qhasm: fe T3 */
+
+/* qhasm: fe YpX1 */
+
+/* qhasm: fe YmX1 */
+
+/* qhasm: fe A */
+
+/* qhasm: fe B */
+
+/* qhasm: fe C */
+
+/* qhasm: fe D */
+
+/* qhasm: YpX1 = Y1+X1 */
+/* asm 1: fe_add(>YpX1=fe#1,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_add(>YpX1=r->X,<Y1=p->Y,<X1=p->X); */
+fe_add(r->X,p->Y,p->X);
+
+/* qhasm: YmX1 = Y1-X1 */
+/* asm 1: fe_sub(>YmX1=fe#2,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_sub(>YmX1=r->Y,<Y1=p->Y,<X1=p->X); */
+fe_sub(r->Y,p->Y,p->X);
+
+/* qhasm: A = YpX1*ymx2 */
+/* asm 1: fe_mul(>A=fe#3,<YpX1=fe#1,<ymx2=fe#16); */
+/* asm 2: fe_mul(>A=r->Z,<YpX1=r->X,<ymx2=q->yminusx); */
+fe_mul(r->Z,r->X,q->yminusx);
+
+/* qhasm: B = YmX1*ypx2 */
+/* asm 1: fe_mul(>B=fe#2,<YmX1=fe#2,<ypx2=fe#15); */
+/* asm 2: fe_mul(>B=r->Y,<YmX1=r->Y,<ypx2=q->yplusx); */
+fe_mul(r->Y,r->Y,q->yplusx);
+
+/* qhasm: C = xy2d2*T1 */
+/* asm 1: fe_mul(>C=fe#4,<xy2d2=fe#17,<T1=fe#14); */
+/* asm 2: fe_mul(>C=r->T,<xy2d2=q->xy2d,<T1=p->T); */
+fe_mul(r->T,q->xy2d,p->T);
+
+/* qhasm: D = 2*Z1 */
+/* asm 1: fe_add(>D=fe#5,<Z1=fe#13,<Z1=fe#13); */
+/* asm 2: fe_add(>D=t0,<Z1=p->Z,<Z1=p->Z); */
+fe_add(t0,p->Z,p->Z);
+
+/* qhasm: X3 = A-B */
+/* asm 1: fe_sub(>X3=fe#1,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_sub(>X3=r->X,<A=r->Z,<B=r->Y); */
+fe_sub(r->X,r->Z,r->Y);
+
+/* qhasm: Y3 = A+B */
+/* asm 1: fe_add(>Y3=fe#2,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_add(>Y3=r->Y,<A=r->Z,<B=r->Y); */
+fe_add(r->Y,r->Z,r->Y);
+
+/* qhasm: Z3 = D-C */
+/* asm 1: fe_sub(>Z3=fe#3,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_sub(>Z3=r->Z,<D=t0,<C=r->T); */
+fe_sub(r->Z,t0,r->T);
+
+/* qhasm: T3 = D+C */
+/* asm 1: fe_add(>T3=fe#4,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_add(>T3=r->T,<D=t0,<C=r->T); */
+fe_add(r->T,t0,r->T);
+
+/* qhasm: return */
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_msub.q b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_msub.q
new file mode 100644
index 0000000000..e3cadd882d
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_msub.q
@@ -0,0 +1,46 @@
+:name:fe:r->X:r->Y:r->Z:r->T:t0:t1:t2:t3:t4:t5:p->X:p->Y:p->Z:p->T:q->yplusx:q->yminusx:q->xy2d:
+fe r:var/r=fe:
+
+enter f:enter/f:>X1=fe#11:>Y1=fe#12:>Z1=fe#13:>T1=fe#14:>ypx2=fe#15:>ymx2=fe#16:>xy2d2=fe#17:
+return:nofallthrough:<X3=fe#1:<Y3=fe#2:<Z3=fe#3:<T3=fe#4:leave:
+
+h=f+g:<f=fe:<g=fe:>h=fe:asm/fe_add(>h,<f,<g);:
+h=f-g:<f=fe:<g=fe:>h=fe:asm/fe_sub(>h,<f,<g);:
+h=f*g:<f=fe:<g=fe:>h=fe:asm/fe_mul(>h,<f,<g);:
+h=f^2:<f=fe:>h=fe:asm/fe_sq(>h,<f);:
+h=2*g:<g=fe:>h=fe:asm/fe_add(>h,<g,<g);:
+
+:
+
+enter ge_msub
+
+fe X1
+fe Y1
+fe Z1
+fe T1
+fe ypx2
+fe ymx2
+fe xy2d2
+fe X3
+fe Y3
+fe Z3
+fe T3
+fe YpX1
+fe YmX1
+fe A
+fe B
+fe C
+fe D
+
+YpX1 = Y1+X1
+YmX1 = Y1-X1
+A = YpX1*ymx2
+B = YmX1*ypx2
+C = xy2d2*T1
+D = 2*Z1
+X3 = A-B
+Y3 = A+B
+Z3 = D-C
+T3 = D+C
+
+return
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p1p1_to_p2.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p1p1_to_p2.c
new file mode 100644
index 0000000000..9bb5013d66
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p1p1_to_p2.c
@@ -0,0 +1,12 @@
+#include "ge.h"
+
+/*
+r = p
+*/
+
+extern void ge_p1p1_to_p2(ge_p2 *r,const ge_p1p1 *p)
+{
+  fe_mul(r->X,p->X,p->T);
+  fe_mul(r->Y,p->Y,p->Z);
+  fe_mul(r->Z,p->Z,p->T);
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p1p1_to_p3.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p1p1_to_p3.c
new file mode 100644
index 0000000000..2f57b10968
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p1p1_to_p3.c
@@ -0,0 +1,13 @@
+#include "ge.h"
+
+/*
+r = p
+*/
+
+extern void ge_p1p1_to_p3(ge_p3 *r,const ge_p1p1 *p)
+{
+  fe_mul(r->X,p->X,p->T);
+  fe_mul(r->Y,p->Y,p->Z);
+  fe_mul(r->Z,p->Z,p->T);
+  fe_mul(r->T,p->X,p->Y);
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p2_0.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p2_0.c
new file mode 100644
index 0000000000..6191d1e6e4
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p2_0.c
@@ -0,0 +1,8 @@
+#include "ge.h"
+
+void ge_p2_0(ge_p2 *h)
+{
+  fe_0(h->X);
+  fe_1(h->Y);
+  fe_1(h->Z);
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p2_dbl.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p2_dbl.c
new file mode 100644
index 0000000000..2e332b5cee
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p2_dbl.c
@@ -0,0 +1,11 @@
+#include "ge.h"
+
+/*
+r = 2 * p
+*/
+
+void ge_p2_dbl(ge_p1p1 *r,const ge_p2 *p)
+{
+  fe t0;
+#include "ge_p2_dbl.h"
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p2_dbl.h b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p2_dbl.h
new file mode 100644
index 0000000000..128efed907
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p2_dbl.h
@@ -0,0 +1,73 @@
+
+/* qhasm: enter ge_p2_dbl */
+
+/* qhasm: fe X1 */
+
+/* qhasm: fe Y1 */
+
+/* qhasm: fe Z1 */
+
+/* qhasm: fe A */
+
+/* qhasm: fe AA */
+
+/* qhasm: fe XX */
+
+/* qhasm: fe YY */
+
+/* qhasm: fe B */
+
+/* qhasm: fe X3 */
+
+/* qhasm: fe Y3 */
+
+/* qhasm: fe Z3 */
+
+/* qhasm: fe T3 */
+
+/* qhasm: XX=X1^2 */
+/* asm 1: fe_sq(>XX=fe#1,<X1=fe#11); */
+/* asm 2: fe_sq(>XX=r->X,<X1=p->X); */
+fe_sq(r->X,p->X);
+
+/* qhasm: YY=Y1^2 */
+/* asm 1: fe_sq(>YY=fe#3,<Y1=fe#12); */
+/* asm 2: fe_sq(>YY=r->Z,<Y1=p->Y); */
+fe_sq(r->Z,p->Y);
+
+/* qhasm: B=2*Z1^2 */
+/* asm 1: fe_sq2(>B=fe#4,<Z1=fe#13); */
+/* asm 2: fe_sq2(>B=r->T,<Z1=p->Z); */
+fe_sq2(r->T,p->Z);
+
+/* qhasm: A=X1+Y1 */
+/* asm 1: fe_add(>A=fe#2,<X1=fe#11,<Y1=fe#12); */
+/* asm 2: fe_add(>A=r->Y,<X1=p->X,<Y1=p->Y); */
+fe_add(r->Y,p->X,p->Y);
+
+/* qhasm: AA=A^2 */
+/* asm 1: fe_sq(>AA=fe#5,<A=fe#2); */
+/* asm 2: fe_sq(>AA=t0,<A=r->Y); */
+fe_sq(t0,r->Y);
+
+/* qhasm: Y3=YY+XX */
+/* asm 1: fe_add(>Y3=fe#2,<YY=fe#3,<XX=fe#1); */
+/* asm 2: fe_add(>Y3=r->Y,<YY=r->Z,<XX=r->X); */
+fe_add(r->Y,r->Z,r->X);
+
+/* qhasm: Z3=YY-XX */
+/* asm 1: fe_sub(>Z3=fe#3,<YY=fe#3,<XX=fe#1); */
+/* asm 2: fe_sub(>Z3=r->Z,<YY=r->Z,<XX=r->X); */
+fe_sub(r->Z,r->Z,r->X);
+
+/* qhasm: X3=AA-Y3 */
+/* asm 1: fe_sub(>X3=fe#1,<AA=fe#5,<Y3=fe#2); */
+/* asm 2: fe_sub(>X3=r->X,<AA=t0,<Y3=r->Y); */
+fe_sub(r->X,t0,r->Y);
+
+/* qhasm: T3=B-Z3 */
+/* asm 1: fe_sub(>T3=fe#4,<B=fe#4,<Z3=fe#3); */
+/* asm 2: fe_sub(>T3=r->T,<B=r->T,<Z3=r->Z); */
+fe_sub(r->T,r->T,r->Z);
+
+/* qhasm: return */
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p2_dbl.q b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p2_dbl.q
new file mode 100644
index 0000000000..170d42f9a7
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p2_dbl.q
@@ -0,0 +1,41 @@
+:name:fe:r->X:r->Y:r->Z:r->T:t0:t1:t2:t3:t4:t5:p->X:p->Y:p->Z:
+fe r:var/r=fe:
+
+enter f:enter/f:>X1=fe#11:>Y1=fe#12:>Z1=fe#13:
+return:nofallthrough:<X3=fe#1:<Y3=fe#2:<Z3=fe#3:<T3=fe#4:leave:
+
+h=f+g:<f=fe:<g=fe:>h=fe:asm/fe_add(>h,<f,<g);:
+h=f-g:<f=fe:<g=fe:>h=fe:asm/fe_sub(>h,<f,<g);:
+h=f*g:<f=fe:<g=fe:>h=fe:asm/fe_mul(>h,<f,<g);:
+h=f^2:<f=fe:>h=fe:asm/fe_sq(>h,<f);:
+h=2*f^2:<f=fe:>h=fe:asm/fe_sq2(>h,<f);:
+h=2*g:<g=fe:>h=fe:asm/fe_add(>h,<g,<g);:
+
+:
+
+enter ge_p2_dbl
+
+fe X1
+fe Y1
+fe Z1
+fe A
+fe AA
+fe XX
+fe YY
+fe B
+fe X3
+fe Y3
+fe Z3
+fe T3
+
+XX=X1^2
+YY=Y1^2
+B=2*Z1^2
+A=X1+Y1
+AA=A^2
+Y3=YY+XX
+Z3=YY-XX
+X3=AA-Y3
+T3=B-Z3
+
+return
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p3_0.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p3_0.c
new file mode 100644
index 0000000000..401b2935a1
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p3_0.c
@@ -0,0 +1,9 @@
+#include "ge.h"
+
+void ge_p3_0(ge_p3 *h)
+{
+  fe_0(h->X);
+  fe_1(h->Y);
+  fe_1(h->Z);
+  fe_0(h->T);
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p3_dbl.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p3_dbl.c
new file mode 100644
index 0000000000..0d8a05915d
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p3_dbl.c
@@ -0,0 +1,12 @@
+#include "ge.h"
+
+/*
+r = 2 * p
+*/
+
+void ge_p3_dbl(ge_p1p1 *r,const ge_p3 *p)
+{
+  ge_p2 q;
+  ge_p3_to_p2(&q,p);
+  ge_p2_dbl(r,&q);
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p3_to_cached.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p3_to_cached.c
new file mode 100644
index 0000000000..bde64228cf
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p3_to_cached.c
@@ -0,0 +1,17 @@
+#include "ge.h"
+
+/*
+r = p
+*/
+
+static const fe d2 = {
+#include "d2.h"
+} ;
+
+extern void ge_p3_to_cached(ge_cached *r,const ge_p3 *p)
+{
+  fe_add(r->YplusX,p->Y,p->X);
+  fe_sub(r->YminusX,p->Y,p->X);
+  fe_copy(r->Z,p->Z);
+  fe_mul(r->T2d,p->T,d2);
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p3_to_p2.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p3_to_p2.c
new file mode 100644
index 0000000000..e532a9e4cb
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p3_to_p2.c
@@ -0,0 +1,12 @@
+#include "ge.h"
+
+/*
+r = p
+*/
+
+extern void ge_p3_to_p2(ge_p2 *r,const ge_p3 *p)
+{
+  fe_copy(r->X,p->X);
+  fe_copy(r->Y,p->Y);
+  fe_copy(r->Z,p->Z);
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p3_tobytes.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p3_tobytes.c
new file mode 100644
index 0000000000..21cb2fc656
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p3_tobytes.c
@@ -0,0 +1,14 @@
+#include "ge.h"
+
+void ge_p3_tobytes(unsigned char *s,const ge_p3 *h)
+{
+  fe recip;
+  fe x;
+  fe y;
+
+  fe_invert(recip,h->Z);
+  fe_mul(x,h->X,recip);
+  fe_mul(y,h->Y,recip);
+  fe_tobytes(s,y);
+  s[31] ^= fe_isnegative(x) << 7;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_precomp_0.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_precomp_0.c
new file mode 100644
index 0000000000..2e218861d8
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_precomp_0.c
@@ -0,0 +1,8 @@
+#include "ge.h"
+
+void ge_precomp_0(ge_precomp *h)
+{
+  fe_1(h->yplusx);
+  fe_1(h->yminusx);
+  fe_0(h->xy2d);
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_scalarmult_base.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_scalarmult_base.c
new file mode 100644
index 0000000000..421e4fa0fb
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_scalarmult_base.c
@@ -0,0 +1,105 @@
+#include "ge.h"
+#include "crypto_uint32.h"
+
+static unsigned char equal(signed char b,signed char c)
+{
+  unsigned char ub = b;
+  unsigned char uc = c;
+  unsigned char x = ub ^ uc; /* 0: yes; 1..255: no */
+  crypto_uint32 y = x; /* 0: yes; 1..255: no */
+  y -= 1; /* 4294967295: yes; 0..254: no */
+  y >>= 31; /* 1: yes; 0: no */
+  return y;
+}
+
+static unsigned char negative(signed char b)
+{
+  unsigned long long x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */
+  x >>= 63; /* 1: yes; 0: no */
+  return x;
+}
+
+static void cmov(ge_precomp *t,ge_precomp *u,unsigned char b)
+{
+  fe_cmov(t->yplusx,u->yplusx,b);
+  fe_cmov(t->yminusx,u->yminusx,b);
+  fe_cmov(t->xy2d,u->xy2d,b);
+}
+
+/* base[i][j] = (j+1)*256^i*B */
+static ge_precomp base[32][8] = {
+#include "base.h"
+} ;
+
+static void select(ge_precomp *t,int pos,signed char b)
+{
+  ge_precomp minust;
+  unsigned char bnegative = negative(b);
+  unsigned char babs = b - (((-bnegative) & b) << 1);
+
+  ge_precomp_0(t);
+  cmov(t,&base[pos][0],equal(babs,1));
+  cmov(t,&base[pos][1],equal(babs,2));
+  cmov(t,&base[pos][2],equal(babs,3));
+  cmov(t,&base[pos][3],equal(babs,4));
+  cmov(t,&base[pos][4],equal(babs,5));
+  cmov(t,&base[pos][5],equal(babs,6));
+  cmov(t,&base[pos][6],equal(babs,7));
+  cmov(t,&base[pos][7],equal(babs,8));
+  fe_copy(minust.yplusx,t->yminusx);
+  fe_copy(minust.yminusx,t->yplusx);
+  fe_neg(minust.xy2d,t->xy2d);
+  cmov(t,&minust,bnegative);
+}
+
+/*
+h = a * B
+where a = a[0]+256*a[1]+...+256^31 a[31]
+B is the Ed25519 base point (x,4/5) with x positive.
+
+Preconditions:
+  a[31] <= 127
+*/
+
+void ge_scalarmult_base(ge_p3 *h,const unsigned char *a)
+{
+  signed char e[64];
+  signed char carry;
+  ge_p1p1 r;
+  ge_p2 s;
+  ge_precomp t;
+  int i;
+
+  for (i = 0;i < 32;++i) {
+    e[2 * i + 0] = (a[i] >> 0) & 15;
+    e[2 * i + 1] = (a[i] >> 4) & 15;
+  }
+  /* each e[i] is between 0 and 15 */
+  /* e[63] is between 0 and 7 */
+
+  carry = 0;
+  for (i = 0;i < 63;++i) {
+    e[i] += carry;
+    carry = e[i] + 8;
+    carry >>= 4;
+    e[i] -= carry << 4;
+  }
+  e[63] += carry;
+  /* each e[i] is between -8 and 8 */
+
+  ge_p3_0(h);
+  for (i = 1;i < 64;i += 2) {
+    select(&t,i / 2,e[i]);
+    ge_madd(&r,h,&t); ge_p1p1_to_p3(h,&r);
+  }
+
+  ge_p3_dbl(&r,h);  ge_p1p1_to_p2(&s,&r);
+  ge_p2_dbl(&r,&s); ge_p1p1_to_p2(&s,&r);
+  ge_p2_dbl(&r,&s); ge_p1p1_to_p2(&s,&r);
+  ge_p2_dbl(&r,&s); ge_p1p1_to_p3(h,&r);
+
+  for (i = 0;i < 64;i += 2) {
+    select(&t,i / 2,e[i]);
+    ge_madd(&r,h,&t); ge_p1p1_to_p3(h,&r);
+  }
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_sub.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_sub.c
new file mode 100644
index 0000000000..69f3d54062
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_sub.c
@@ -0,0 +1,11 @@
+#include "ge.h"
+
+/*
+r = p - q
+*/
+
+void ge_sub(ge_p1p1 *r,const ge_p3 *p,const ge_cached *q)
+{
+  fe t0;
+#include "ge_sub.h"
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_sub.h b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_sub.h
new file mode 100644
index 0000000000..b4ef1f5dd0
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_sub.h
@@ -0,0 +1,97 @@
+
+/* qhasm: enter ge_sub */
+
+/* qhasm: fe X1 */
+
+/* qhasm: fe Y1 */
+
+/* qhasm: fe Z1 */
+
+/* qhasm: fe Z2 */
+
+/* qhasm: fe T1 */
+
+/* qhasm: fe ZZ */
+
+/* qhasm: fe YpX2 */
+
+/* qhasm: fe YmX2 */
+
+/* qhasm: fe T2d2 */
+
+/* qhasm: fe X3 */
+
+/* qhasm: fe Y3 */
+
+/* qhasm: fe Z3 */
+
+/* qhasm: fe T3 */
+
+/* qhasm: fe YpX1 */
+
+/* qhasm: fe YmX1 */
+
+/* qhasm: fe A */
+
+/* qhasm: fe B */
+
+/* qhasm: fe C */
+
+/* qhasm: fe D */
+
+/* qhasm: YpX1 = Y1+X1 */
+/* asm 1: fe_add(>YpX1=fe#1,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_add(>YpX1=r->X,<Y1=p->Y,<X1=p->X); */
+fe_add(r->X,p->Y,p->X);
+
+/* qhasm: YmX1 = Y1-X1 */
+/* asm 1: fe_sub(>YmX1=fe#2,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_sub(>YmX1=r->Y,<Y1=p->Y,<X1=p->X); */
+fe_sub(r->Y,p->Y,p->X);
+
+/* qhasm: A = YpX1*YmX2 */
+/* asm 1: fe_mul(>A=fe#3,<YpX1=fe#1,<YmX2=fe#16); */
+/* asm 2: fe_mul(>A=r->Z,<YpX1=r->X,<YmX2=q->YminusX); */
+fe_mul(r->Z,r->X,q->YminusX);
+
+/* qhasm: B = YmX1*YpX2 */
+/* asm 1: fe_mul(>B=fe#2,<YmX1=fe#2,<YpX2=fe#15); */
+/* asm 2: fe_mul(>B=r->Y,<YmX1=r->Y,<YpX2=q->YplusX); */
+fe_mul(r->Y,r->Y,q->YplusX);
+
+/* qhasm: C = T2d2*T1 */
+/* asm 1: fe_mul(>C=fe#4,<T2d2=fe#18,<T1=fe#14); */
+/* asm 2: fe_mul(>C=r->T,<T2d2=q->T2d,<T1=p->T); */
+fe_mul(r->T,q->T2d,p->T);
+
+/* qhasm: ZZ = Z1*Z2 */
+/* asm 1: fe_mul(>ZZ=fe#1,<Z1=fe#13,<Z2=fe#17); */
+/* asm 2: fe_mul(>ZZ=r->X,<Z1=p->Z,<Z2=q->Z); */
+fe_mul(r->X,p->Z,q->Z);
+
+/* qhasm: D = 2*ZZ */
+/* asm 1: fe_add(>D=fe#5,<ZZ=fe#1,<ZZ=fe#1); */
+/* asm 2: fe_add(>D=t0,<ZZ=r->X,<ZZ=r->X); */
+fe_add(t0,r->X,r->X);
+
+/* qhasm: X3 = A-B */
+/* asm 1: fe_sub(>X3=fe#1,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_sub(>X3=r->X,<A=r->Z,<B=r->Y); */
+fe_sub(r->X,r->Z,r->Y);
+
+/* qhasm: Y3 = A+B */
+/* asm 1: fe_add(>Y3=fe#2,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_add(>Y3=r->Y,<A=r->Z,<B=r->Y); */
+fe_add(r->Y,r->Z,r->Y);
+
+/* qhasm: Z3 = D-C */
+/* asm 1: fe_sub(>Z3=fe#3,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_sub(>Z3=r->Z,<D=t0,<C=r->T); */
+fe_sub(r->Z,t0,r->T);
+
+/* qhasm: T3 = D+C */
+/* asm 1: fe_add(>T3=fe#4,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_add(>T3=r->T,<D=t0,<C=r->T); */
+fe_add(r->T,t0,r->T);
+
+/* qhasm: return */
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_sub.q b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_sub.q
new file mode 100644
index 0000000000..2779a4a201
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_sub.q
@@ -0,0 +1,49 @@
+:name:fe:r->X:r->Y:r->Z:r->T:t0:t1:t2:t3:t4:t5:p->X:p->Y:p->Z:p->T:q->YplusX:q->YminusX:q->Z:q->T2d:
+fe r:var/r=fe:
+
+enter f:enter/f:>X1=fe#11:>Y1=fe#12:>Z1=fe#13:>T1=fe#14:>YpX2=fe#15:>YmX2=fe#16:>Z2=fe#17:>T2d2=fe#18:
+return:nofallthrough:<X3=fe#1:<Y3=fe#2:<Z3=fe#3:<T3=fe#4:leave:
+
+h=f+g:<f=fe:<g=fe:>h=fe:asm/fe_add(>h,<f,<g);:
+h=f-g:<f=fe:<g=fe:>h=fe:asm/fe_sub(>h,<f,<g);:
+h=f*g:<f=fe:<g=fe:>h=fe:asm/fe_mul(>h,<f,<g);:
+h=f^2:<f=fe:>h=fe:asm/fe_sq(>h,<f);:
+h=2*g:<g=fe:>h=fe:asm/fe_add(>h,<g,<g);:
+
+:
+
+enter ge_sub
+
+fe X1
+fe Y1
+fe Z1
+fe Z2
+fe T1
+fe ZZ
+fe YpX2
+fe YmX2
+fe T2d2
+fe X3
+fe Y3
+fe Z3
+fe T3
+fe YpX1
+fe YmX1
+fe A
+fe B
+fe C
+fe D
+
+YpX1 = Y1+X1
+YmX1 = Y1-X1
+A = YpX1*YmX2
+B = YmX1*YpX2
+C = T2d2*T1
+ZZ = Z1*Z2
+D = 2*ZZ
+X3 = A-B
+Y3 = A+B
+Z3 = D-C
+T3 = D+C
+
+return
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_tobytes.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_tobytes.c
new file mode 100644
index 0000000000..31b3d33e09
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_tobytes.c
@@ -0,0 +1,14 @@
+#include "ge.h"
+
+void ge_tobytes(unsigned char *s,const ge_p2 *h)
+{
+  fe recip;
+  fe x;
+  fe y;
+
+  fe_invert(recip,h->Z);
+  fe_mul(x,h->X,recip);
+  fe_mul(y,h->Y,recip);
+  fe_tobytes(s,y);
+  s[31] ^= fe_isnegative(x) << 7;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/keypair.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/keypair.c
new file mode 100644
index 0000000000..ac6cea2b7a
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/keypair.c
@@ -0,0 +1,23 @@
+#include <string.h>
+#include "randombytes.h"
+#include "crypto_sign.h"
+#include "crypto_hash_sha512.h"
+#include "ge.h"
+
+int crypto_sign_keypair(unsigned char *pk,unsigned char *sk)
+{
+  unsigned char az[64];
+  ge_p3 A;
+
+  randombytes(sk,32);
+  crypto_hash_sha512(az,sk,32);
+  az[0] &= 248;
+  az[31] &= 63;
+  az[31] |= 64;
+
+  ge_scalarmult_base(&A,az);
+  ge_p3_tobytes(pk,&A);
+
+  memmove(sk + 32,pk,32);
+  return 0;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/open.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/open.c
new file mode 100644
index 0000000000..1ec4cd2bfd
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/open.c
@@ -0,0 +1,48 @@
+#include <string.h>
+#include "crypto_sign.h"
+#include "crypto_hash_sha512.h"
+#include "crypto_verify_32.h"
+#include "ge.h"
+#include "sc.h"
+
+int crypto_sign_open(
+  unsigned char *m,unsigned long long *mlen,
+  const unsigned char *sm,unsigned long long smlen,
+  const unsigned char *pk
+)
+{
+  unsigned char pkcopy[32];
+  unsigned char rcopy[32];
+  unsigned char scopy[32];
+  unsigned char h[64];
+  unsigned char rcheck[32];
+  ge_p3 A;
+  ge_p2 R;
+
+  if (smlen < 64) goto badsig;
+  if (sm[63] & 224) goto badsig;
+  if (ge_frombytes_negate_vartime(&A,pk) != 0) goto badsig;
+
+  memmove(pkcopy,pk,32);
+  memmove(rcopy,sm,32);
+  memmove(scopy,sm + 32,32);
+
+  memmove(m,sm,smlen);
+  memmove(m + 32,pkcopy,32);
+  crypto_hash_sha512(h,m,smlen);
+  sc_reduce(h);
+
+  ge_double_scalarmult_vartime(&R,h,&A,scopy);
+  ge_tobytes(rcheck,&R);
+  if (crypto_verify_32(rcheck,rcopy) == 0) {
+    memmove(m,m + 64,smlen - 64);
+    memset(m + smlen - 64,0,64);
+    *mlen = smlen - 64;
+    return 0;
+  }
+
+badsig:
+  *mlen = -1;
+  memset(m,0,smlen);
+  return -1;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/pow22523.h b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/pow22523.h
new file mode 100644
index 0000000000..60ffe0d34c
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/pow22523.h
@@ -0,0 +1,160 @@
+
+/* qhasm: fe z1 */
+
+/* qhasm: fe z2 */
+
+/* qhasm: fe z8 */
+
+/* qhasm: fe z9 */
+
+/* qhasm: fe z11 */
+
+/* qhasm: fe z22 */
+
+/* qhasm: fe z_5_0 */
+
+/* qhasm: fe z_10_5 */
+
+/* qhasm: fe z_10_0 */
+
+/* qhasm: fe z_20_10 */
+
+/* qhasm: fe z_20_0 */
+
+/* qhasm: fe z_40_20 */
+
+/* qhasm: fe z_40_0 */
+
+/* qhasm: fe z_50_10 */
+
+/* qhasm: fe z_50_0 */
+
+/* qhasm: fe z_100_50 */
+
+/* qhasm: fe z_100_0 */
+
+/* qhasm: fe z_200_100 */
+
+/* qhasm: fe z_200_0 */
+
+/* qhasm: fe z_250_50 */
+
+/* qhasm: fe z_250_0 */
+
+/* qhasm: fe z_252_2 */
+
+/* qhasm: fe z_252_3 */
+
+/* qhasm: enter pow22523 */
+
+/* qhasm: z2 = z1^2^1 */
+/* asm 1: fe_sq(>z2=fe#1,<z1=fe#11); for (i = 1;i < 1;++i) fe_sq(>z2=fe#1,>z2=fe#1); */
+/* asm 2: fe_sq(>z2=t0,<z1=z); for (i = 1;i < 1;++i) fe_sq(>z2=t0,>z2=t0); */
+fe_sq(t0,z); for (i = 1;i < 1;++i) fe_sq(t0,t0);
+
+/* qhasm: z8 = z2^2^2 */
+/* asm 1: fe_sq(>z8=fe#2,<z2=fe#1); for (i = 1;i < 2;++i) fe_sq(>z8=fe#2,>z8=fe#2); */
+/* asm 2: fe_sq(>z8=t1,<z2=t0); for (i = 1;i < 2;++i) fe_sq(>z8=t1,>z8=t1); */
+fe_sq(t1,t0); for (i = 1;i < 2;++i) fe_sq(t1,t1);
+
+/* qhasm: z9 = z1*z8 */
+/* asm 1: fe_mul(>z9=fe#2,<z1=fe#11,<z8=fe#2); */
+/* asm 2: fe_mul(>z9=t1,<z1=z,<z8=t1); */
+fe_mul(t1,z,t1);
+
+/* qhasm: z11 = z2*z9 */
+/* asm 1: fe_mul(>z11=fe#1,<z2=fe#1,<z9=fe#2); */
+/* asm 2: fe_mul(>z11=t0,<z2=t0,<z9=t1); */
+fe_mul(t0,t0,t1);
+
+/* qhasm: z22 = z11^2^1 */
+/* asm 1: fe_sq(>z22=fe#1,<z11=fe#1); for (i = 1;i < 1;++i) fe_sq(>z22=fe#1,>z22=fe#1); */
+/* asm 2: fe_sq(>z22=t0,<z11=t0); for (i = 1;i < 1;++i) fe_sq(>z22=t0,>z22=t0); */
+fe_sq(t0,t0); for (i = 1;i < 1;++i) fe_sq(t0,t0);
+
+/* qhasm: z_5_0 = z9*z22 */
+/* asm 1: fe_mul(>z_5_0=fe#1,<z9=fe#2,<z22=fe#1); */
+/* asm 2: fe_mul(>z_5_0=t0,<z9=t1,<z22=t0); */
+fe_mul(t0,t1,t0);
+
+/* qhasm: z_10_5 = z_5_0^2^5 */
+/* asm 1: fe_sq(>z_10_5=fe#2,<z_5_0=fe#1); for (i = 1;i < 5;++i) fe_sq(>z_10_5=fe#2,>z_10_5=fe#2); */
+/* asm 2: fe_sq(>z_10_5=t1,<z_5_0=t0); for (i = 1;i < 5;++i) fe_sq(>z_10_5=t1,>z_10_5=t1); */
+fe_sq(t1,t0); for (i = 1;i < 5;++i) fe_sq(t1,t1);
+
+/* qhasm: z_10_0 = z_10_5*z_5_0 */
+/* asm 1: fe_mul(>z_10_0=fe#1,<z_10_5=fe#2,<z_5_0=fe#1); */
+/* asm 2: fe_mul(>z_10_0=t0,<z_10_5=t1,<z_5_0=t0); */
+fe_mul(t0,t1,t0);
+
+/* qhasm: z_20_10 = z_10_0^2^10 */
+/* asm 1: fe_sq(>z_20_10=fe#2,<z_10_0=fe#1); for (i = 1;i < 10;++i) fe_sq(>z_20_10=fe#2,>z_20_10=fe#2); */
+/* asm 2: fe_sq(>z_20_10=t1,<z_10_0=t0); for (i = 1;i < 10;++i) fe_sq(>z_20_10=t1,>z_20_10=t1); */
+fe_sq(t1,t0); for (i = 1;i < 10;++i) fe_sq(t1,t1);
+
+/* qhasm: z_20_0 = z_20_10*z_10_0 */
+/* asm 1: fe_mul(>z_20_0=fe#2,<z_20_10=fe#2,<z_10_0=fe#1); */
+/* asm 2: fe_mul(>z_20_0=t1,<z_20_10=t1,<z_10_0=t0); */
+fe_mul(t1,t1,t0);
+
+/* qhasm: z_40_20 = z_20_0^2^20 */
+/* asm 1: fe_sq(>z_40_20=fe#3,<z_20_0=fe#2); for (i = 1;i < 20;++i) fe_sq(>z_40_20=fe#3,>z_40_20=fe#3); */
+/* asm 2: fe_sq(>z_40_20=t2,<z_20_0=t1); for (i = 1;i < 20;++i) fe_sq(>z_40_20=t2,>z_40_20=t2); */
+fe_sq(t2,t1); for (i = 1;i < 20;++i) fe_sq(t2,t2);
+
+/* qhasm: z_40_0 = z_40_20*z_20_0 */
+/* asm 1: fe_mul(>z_40_0=fe#2,<z_40_20=fe#3,<z_20_0=fe#2); */
+/* asm 2: fe_mul(>z_40_0=t1,<z_40_20=t2,<z_20_0=t1); */
+fe_mul(t1,t2,t1);
+
+/* qhasm: z_50_10 = z_40_0^2^10 */
+/* asm 1: fe_sq(>z_50_10=fe#2,<z_40_0=fe#2); for (i = 1;i < 10;++i) fe_sq(>z_50_10=fe#2,>z_50_10=fe#2); */
+/* asm 2: fe_sq(>z_50_10=t1,<z_40_0=t1); for (i = 1;i < 10;++i) fe_sq(>z_50_10=t1,>z_50_10=t1); */
+fe_sq(t1,t1); for (i = 1;i < 10;++i) fe_sq(t1,t1);
+
+/* qhasm: z_50_0 = z_50_10*z_10_0 */
+/* asm 1: fe_mul(>z_50_0=fe#1,<z_50_10=fe#2,<z_10_0=fe#1); */
+/* asm 2: fe_mul(>z_50_0=t0,<z_50_10=t1,<z_10_0=t0); */
+fe_mul(t0,t1,t0);
+
+/* qhasm: z_100_50 = z_50_0^2^50 */
+/* asm 1: fe_sq(>z_100_50=fe#2,<z_50_0=fe#1); for (i = 1;i < 50;++i) fe_sq(>z_100_50=fe#2,>z_100_50=fe#2); */
+/* asm 2: fe_sq(>z_100_50=t1,<z_50_0=t0); for (i = 1;i < 50;++i) fe_sq(>z_100_50=t1,>z_100_50=t1); */
+fe_sq(t1,t0); for (i = 1;i < 50;++i) fe_sq(t1,t1);
+
+/* qhasm: z_100_0 = z_100_50*z_50_0 */
+/* asm 1: fe_mul(>z_100_0=fe#2,<z_100_50=fe#2,<z_50_0=fe#1); */
+/* asm 2: fe_mul(>z_100_0=t1,<z_100_50=t1,<z_50_0=t0); */
+fe_mul(t1,t1,t0);
+
+/* qhasm: z_200_100 = z_100_0^2^100 */
+/* asm 1: fe_sq(>z_200_100=fe#3,<z_100_0=fe#2); for (i = 1;i < 100;++i) fe_sq(>z_200_100=fe#3,>z_200_100=fe#3); */
+/* asm 2: fe_sq(>z_200_100=t2,<z_100_0=t1); for (i = 1;i < 100;++i) fe_sq(>z_200_100=t2,>z_200_100=t2); */
+fe_sq(t2,t1); for (i = 1;i < 100;++i) fe_sq(t2,t2);
+
+/* qhasm: z_200_0 = z_200_100*z_100_0 */
+/* asm 1: fe_mul(>z_200_0=fe#2,<z_200_100=fe#3,<z_100_0=fe#2); */
+/* asm 2: fe_mul(>z_200_0=t1,<z_200_100=t2,<z_100_0=t1); */
+fe_mul(t1,t2,t1);
+
+/* qhasm: z_250_50 = z_200_0^2^50 */
+/* asm 1: fe_sq(>z_250_50=fe#2,<z_200_0=fe#2); for (i = 1;i < 50;++i) fe_sq(>z_250_50=fe#2,>z_250_50=fe#2); */
+/* asm 2: fe_sq(>z_250_50=t1,<z_200_0=t1); for (i = 1;i < 50;++i) fe_sq(>z_250_50=t1,>z_250_50=t1); */
+fe_sq(t1,t1); for (i = 1;i < 50;++i) fe_sq(t1,t1);
+
+/* qhasm: z_250_0 = z_250_50*z_50_0 */
+/* asm 1: fe_mul(>z_250_0=fe#1,<z_250_50=fe#2,<z_50_0=fe#1); */
+/* asm 2: fe_mul(>z_250_0=t0,<z_250_50=t1,<z_50_0=t0); */
+fe_mul(t0,t1,t0);
+
+/* qhasm: z_252_2 = z_250_0^2^2 */
+/* asm 1: fe_sq(>z_252_2=fe#1,<z_250_0=fe#1); for (i = 1;i < 2;++i) fe_sq(>z_252_2=fe#1,>z_252_2=fe#1); */
+/* asm 2: fe_sq(>z_252_2=t0,<z_250_0=t0); for (i = 1;i < 2;++i) fe_sq(>z_252_2=t0,>z_252_2=t0); */
+fe_sq(t0,t0); for (i = 1;i < 2;++i) fe_sq(t0,t0);
+
+/* qhasm: z_252_3 = z_252_2*z1 */
+/* asm 1: fe_mul(>z_252_3=fe#12,<z_252_2=fe#1,<z1=fe#11); */
+/* asm 2: fe_mul(>z_252_3=out,<z_252_2=t0,<z1=z); */
+fe_mul(out,t0,z);
+
+/* qhasm: return */
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/pow22523.q b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/pow22523.q
new file mode 100644
index 0000000000..2ce1da9d4d
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/pow22523.q
@@ -0,0 +1,61 @@
+:name:fe:t0:t1:t2:t3:t4:t5:t6:t7:t8:t9:z:out:
+fe r:var/r=fe:
+
+enter f:enter/f:>z1=fe#11:
+return:nofallthrough:<z_252_3=fe#12:leave:
+
+h=f*g:<f=fe:<g=fe:>h=fe:asm/fe_mul(>h,<f,<g);:
+h=f^2^k:<f=fe:>h=fe:#k:asm/fe_sq(>h,<f); for (i = 1;i !lt; #k;++i) fe_sq(>h,>h);:
+
+:
+
+fe z1
+fe z2
+fe z8
+fe z9
+fe z11
+fe z22
+fe z_5_0
+fe z_10_5
+fe z_10_0
+fe z_20_10
+fe z_20_0
+fe z_40_20
+fe z_40_0
+fe z_50_10
+fe z_50_0
+fe z_100_50
+fe z_100_0
+fe z_200_100
+fe z_200_0
+fe z_250_50
+fe z_250_0
+fe z_252_2
+fe z_252_3
+
+enter pow22523
+
+z2 = z1^2^1
+z8 = z2^2^2
+z9 = z1*z8
+z11 = z2*z9
+z22 = z11^2^1
+z_5_0 = z9*z22
+z_10_5 = z_5_0^2^5
+z_10_0 = z_10_5*z_5_0
+z_20_10 = z_10_0^2^10
+z_20_0 = z_20_10*z_10_0
+z_40_20 = z_20_0^2^20
+z_40_0 = z_40_20*z_20_0
+z_50_10 = z_40_0^2^10
+z_50_0 = z_50_10*z_10_0
+z_100_50 = z_50_0^2^50
+z_100_0 = z_100_50*z_50_0
+z_200_100 = z_100_0^2^100
+z_200_0 = z_200_100*z_100_0
+z_250_50 = z_200_0^2^50
+z_250_0 = z_250_50*z_50_0
+z_252_2 = z_250_0^2^2
+z_252_3 = z_252_2*z1
+
+return
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/pow225521.h b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/pow225521.h
new file mode 100644
index 0000000000..109df779a2
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/pow225521.h
@@ -0,0 +1,160 @@
+
+/* qhasm: fe z1 */
+
+/* qhasm: fe z2 */
+
+/* qhasm: fe z8 */
+
+/* qhasm: fe z9 */
+
+/* qhasm: fe z11 */
+
+/* qhasm: fe z22 */
+
+/* qhasm: fe z_5_0 */
+
+/* qhasm: fe z_10_5 */
+
+/* qhasm: fe z_10_0 */
+
+/* qhasm: fe z_20_10 */
+
+/* qhasm: fe z_20_0 */
+
+/* qhasm: fe z_40_20 */
+
+/* qhasm: fe z_40_0 */
+
+/* qhasm: fe z_50_10 */
+
+/* qhasm: fe z_50_0 */
+
+/* qhasm: fe z_100_50 */
+
+/* qhasm: fe z_100_0 */
+
+/* qhasm: fe z_200_100 */
+
+/* qhasm: fe z_200_0 */
+
+/* qhasm: fe z_250_50 */
+
+/* qhasm: fe z_250_0 */
+
+/* qhasm: fe z_255_5 */
+
+/* qhasm: fe z_255_21 */
+
+/* qhasm: enter pow225521 */
+
+/* qhasm: z2 = z1^2^1 */
+/* asm 1: fe_sq(>z2=fe#1,<z1=fe#11); for (i = 1;i < 1;++i) fe_sq(>z2=fe#1,>z2=fe#1); */
+/* asm 2: fe_sq(>z2=t0,<z1=z); for (i = 1;i < 1;++i) fe_sq(>z2=t0,>z2=t0); */
+fe_sq(t0,z); for (i = 1;i < 1;++i) fe_sq(t0,t0);
+
+/* qhasm: z8 = z2^2^2 */
+/* asm 1: fe_sq(>z8=fe#2,<z2=fe#1); for (i = 1;i < 2;++i) fe_sq(>z8=fe#2,>z8=fe#2); */
+/* asm 2: fe_sq(>z8=t1,<z2=t0); for (i = 1;i < 2;++i) fe_sq(>z8=t1,>z8=t1); */
+fe_sq(t1,t0); for (i = 1;i < 2;++i) fe_sq(t1,t1);
+
+/* qhasm: z9 = z1*z8 */
+/* asm 1: fe_mul(>z9=fe#2,<z1=fe#11,<z8=fe#2); */
+/* asm 2: fe_mul(>z9=t1,<z1=z,<z8=t1); */
+fe_mul(t1,z,t1);
+
+/* qhasm: z11 = z2*z9 */
+/* asm 1: fe_mul(>z11=fe#1,<z2=fe#1,<z9=fe#2); */
+/* asm 2: fe_mul(>z11=t0,<z2=t0,<z9=t1); */
+fe_mul(t0,t0,t1);
+
+/* qhasm: z22 = z11^2^1 */
+/* asm 1: fe_sq(>z22=fe#3,<z11=fe#1); for (i = 1;i < 1;++i) fe_sq(>z22=fe#3,>z22=fe#3); */
+/* asm 2: fe_sq(>z22=t2,<z11=t0); for (i = 1;i < 1;++i) fe_sq(>z22=t2,>z22=t2); */
+fe_sq(t2,t0); for (i = 1;i < 1;++i) fe_sq(t2,t2);
+
+/* qhasm: z_5_0 = z9*z22 */
+/* asm 1: fe_mul(>z_5_0=fe#2,<z9=fe#2,<z22=fe#3); */
+/* asm 2: fe_mul(>z_5_0=t1,<z9=t1,<z22=t2); */
+fe_mul(t1,t1,t2);
+
+/* qhasm: z_10_5 = z_5_0^2^5 */
+/* asm 1: fe_sq(>z_10_5=fe#3,<z_5_0=fe#2); for (i = 1;i < 5;++i) fe_sq(>z_10_5=fe#3,>z_10_5=fe#3); */
+/* asm 2: fe_sq(>z_10_5=t2,<z_5_0=t1); for (i = 1;i < 5;++i) fe_sq(>z_10_5=t2,>z_10_5=t2); */
+fe_sq(t2,t1); for (i = 1;i < 5;++i) fe_sq(t2,t2);
+
+/* qhasm: z_10_0 = z_10_5*z_5_0 */
+/* asm 1: fe_mul(>z_10_0=fe#2,<z_10_5=fe#3,<z_5_0=fe#2); */
+/* asm 2: fe_mul(>z_10_0=t1,<z_10_5=t2,<z_5_0=t1); */
+fe_mul(t1,t2,t1);
+
+/* qhasm: z_20_10 = z_10_0^2^10 */
+/* asm 1: fe_sq(>z_20_10=fe#3,<z_10_0=fe#2); for (i = 1;i < 10;++i) fe_sq(>z_20_10=fe#3,>z_20_10=fe#3); */
+/* asm 2: fe_sq(>z_20_10=t2,<z_10_0=t1); for (i = 1;i < 10;++i) fe_sq(>z_20_10=t2,>z_20_10=t2); */
+fe_sq(t2,t1); for (i = 1;i < 10;++i) fe_sq(t2,t2);
+
+/* qhasm: z_20_0 = z_20_10*z_10_0 */
+/* asm 1: fe_mul(>z_20_0=fe#3,<z_20_10=fe#3,<z_10_0=fe#2); */
+/* asm 2: fe_mul(>z_20_0=t2,<z_20_10=t2,<z_10_0=t1); */
+fe_mul(t2,t2,t1);
+
+/* qhasm: z_40_20 = z_20_0^2^20 */
+/* asm 1: fe_sq(>z_40_20=fe#4,<z_20_0=fe#3); for (i = 1;i < 20;++i) fe_sq(>z_40_20=fe#4,>z_40_20=fe#4); */
+/* asm 2: fe_sq(>z_40_20=t3,<z_20_0=t2); for (i = 1;i < 20;++i) fe_sq(>z_40_20=t3,>z_40_20=t3); */
+fe_sq(t3,t2); for (i = 1;i < 20;++i) fe_sq(t3,t3);
+
+/* qhasm: z_40_0 = z_40_20*z_20_0 */
+/* asm 1: fe_mul(>z_40_0=fe#3,<z_40_20=fe#4,<z_20_0=fe#3); */
+/* asm 2: fe_mul(>z_40_0=t2,<z_40_20=t3,<z_20_0=t2); */
+fe_mul(t2,t3,t2);
+
+/* qhasm: z_50_10 = z_40_0^2^10 */
+/* asm 1: fe_sq(>z_50_10=fe#3,<z_40_0=fe#3); for (i = 1;i < 10;++i) fe_sq(>z_50_10=fe#3,>z_50_10=fe#3); */
+/* asm 2: fe_sq(>z_50_10=t2,<z_40_0=t2); for (i = 1;i < 10;++i) fe_sq(>z_50_10=t2,>z_50_10=t2); */
+fe_sq(t2,t2); for (i = 1;i < 10;++i) fe_sq(t2,t2);
+
+/* qhasm: z_50_0 = z_50_10*z_10_0 */
+/* asm 1: fe_mul(>z_50_0=fe#2,<z_50_10=fe#3,<z_10_0=fe#2); */
+/* asm 2: fe_mul(>z_50_0=t1,<z_50_10=t2,<z_10_0=t1); */
+fe_mul(t1,t2,t1);
+
+/* qhasm: z_100_50 = z_50_0^2^50 */
+/* asm 1: fe_sq(>z_100_50=fe#3,<z_50_0=fe#2); for (i = 1;i < 50;++i) fe_sq(>z_100_50=fe#3,>z_100_50=fe#3); */
+/* asm 2: fe_sq(>z_100_50=t2,<z_50_0=t1); for (i = 1;i < 50;++i) fe_sq(>z_100_50=t2,>z_100_50=t2); */
+fe_sq(t2,t1); for (i = 1;i < 50;++i) fe_sq(t2,t2);
+
+/* qhasm: z_100_0 = z_100_50*z_50_0 */
+/* asm 1: fe_mul(>z_100_0=fe#3,<z_100_50=fe#3,<z_50_0=fe#2); */
+/* asm 2: fe_mul(>z_100_0=t2,<z_100_50=t2,<z_50_0=t1); */
+fe_mul(t2,t2,t1);
+
+/* qhasm: z_200_100 = z_100_0^2^100 */
+/* asm 1: fe_sq(>z_200_100=fe#4,<z_100_0=fe#3); for (i = 1;i < 100;++i) fe_sq(>z_200_100=fe#4,>z_200_100=fe#4); */
+/* asm 2: fe_sq(>z_200_100=t3,<z_100_0=t2); for (i = 1;i < 100;++i) fe_sq(>z_200_100=t3,>z_200_100=t3); */
+fe_sq(t3,t2); for (i = 1;i < 100;++i) fe_sq(t3,t3);
+
+/* qhasm: z_200_0 = z_200_100*z_100_0 */
+/* asm 1: fe_mul(>z_200_0=fe#3,<z_200_100=fe#4,<z_100_0=fe#3); */
+/* asm 2: fe_mul(>z_200_0=t2,<z_200_100=t3,<z_100_0=t2); */
+fe_mul(t2,t3,t2);
+
+/* qhasm: z_250_50 = z_200_0^2^50 */
+/* asm 1: fe_sq(>z_250_50=fe#3,<z_200_0=fe#3); for (i = 1;i < 50;++i) fe_sq(>z_250_50=fe#3,>z_250_50=fe#3); */
+/* asm 2: fe_sq(>z_250_50=t2,<z_200_0=t2); for (i = 1;i < 50;++i) fe_sq(>z_250_50=t2,>z_250_50=t2); */
+fe_sq(t2,t2); for (i = 1;i < 50;++i) fe_sq(t2,t2);
+
+/* qhasm: z_250_0 = z_250_50*z_50_0 */
+/* asm 1: fe_mul(>z_250_0=fe#2,<z_250_50=fe#3,<z_50_0=fe#2); */
+/* asm 2: fe_mul(>z_250_0=t1,<z_250_50=t2,<z_50_0=t1); */
+fe_mul(t1,t2,t1);
+
+/* qhasm: z_255_5 = z_250_0^2^5 */
+/* asm 1: fe_sq(>z_255_5=fe#2,<z_250_0=fe#2); for (i = 1;i < 5;++i) fe_sq(>z_255_5=fe#2,>z_255_5=fe#2); */
+/* asm 2: fe_sq(>z_255_5=t1,<z_250_0=t1); for (i = 1;i < 5;++i) fe_sq(>z_255_5=t1,>z_255_5=t1); */
+fe_sq(t1,t1); for (i = 1;i < 5;++i) fe_sq(t1,t1);
+
+/* qhasm: z_255_21 = z_255_5*z11 */
+/* asm 1: fe_mul(>z_255_21=fe#12,<z_255_5=fe#2,<z11=fe#1); */
+/* asm 2: fe_mul(>z_255_21=out,<z_255_5=t1,<z11=t0); */
+fe_mul(out,t1,t0);
+
+/* qhasm: return */
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/pow225521.q b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/pow225521.q
new file mode 100644
index 0000000000..45be57c08a
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/pow225521.q
@@ -0,0 +1,61 @@
+:name:fe:t0:t1:t2:t3:t4:t5:t6:t7:t8:t9:z:out:
+fe r:var/r=fe:
+
+enter f:enter/f:>z1=fe#11:
+return:nofallthrough:<z_255_21=fe#12:leave:
+
+h=f*g:<f=fe:<g=fe:>h=fe:asm/fe_mul(>h,<f,<g);:
+h=f^2^k:<f=fe:>h=fe:#k:asm/fe_sq(>h,<f); for (i = 1;i !lt; #k;++i) fe_sq(>h,>h);:
+
+:
+
+fe z1
+fe z2
+fe z8
+fe z9
+fe z11
+fe z22
+fe z_5_0
+fe z_10_5
+fe z_10_0
+fe z_20_10
+fe z_20_0
+fe z_40_20
+fe z_40_0
+fe z_50_10
+fe z_50_0
+fe z_100_50
+fe z_100_0
+fe z_200_100
+fe z_200_0
+fe z_250_50
+fe z_250_0
+fe z_255_5
+fe z_255_21
+
+enter pow225521
+
+z2 = z1^2^1
+z8 = z2^2^2
+z9 = z1*z8
+z11 = z2*z9
+z22 = z11^2^1
+z_5_0 = z9*z22
+z_10_5 = z_5_0^2^5
+z_10_0 = z_10_5*z_5_0
+z_20_10 = z_10_0^2^10
+z_20_0 = z_20_10*z_10_0
+z_40_20 = z_20_0^2^20
+z_40_0 = z_40_20*z_20_0
+z_50_10 = z_40_0^2^10
+z_50_0 = z_50_10*z_10_0
+z_100_50 = z_50_0^2^50
+z_100_0 = z_100_50*z_50_0
+z_200_100 = z_100_0^2^100
+z_200_0 = z_200_100*z_100_0
+z_250_50 = z_200_0^2^50
+z_250_0 = z_250_50*z_50_0
+z_255_5 = z_250_0^2^5
+z_255_21 = z_255_5*z11
+
+return
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/q2h.sh b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/q2h.sh
new file mode 100644
index 0000000000..47ec5110e8
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/q2h.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+sed 's/^#.*//' \
+| qhasm-generic \
+| sed 's_//\(.*\)$_/*\1 */_'
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sc.h b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sc.h
new file mode 100644
index 0000000000..d32ed2e8ca
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sc.h
@@ -0,0 +1,15 @@
+#ifndef SC_H
+#define SC_H
+
+/*
+The set of scalars is \Z/l
+where l = 2^252 + 27742317777372353535851937790883648493.
+*/
+
+#define sc_reduce crypto_sign_ed25519_ref10_sc_reduce
+#define sc_muladd crypto_sign_ed25519_ref10_sc_muladd
+
+extern void sc_reduce(unsigned char *);
+extern void sc_muladd(unsigned char *,const unsigned char *,const unsigned char *,const unsigned char *);
+
+#endif
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sc_muladd.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sc_muladd.c
new file mode 100644
index 0000000000..6f1e9d02d6
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sc_muladd.c
@@ -0,0 +1,368 @@
+#include "sc.h"
+#include "crypto_int64.h"
+#include "crypto_uint32.h"
+#include "crypto_uint64.h"
+
+static crypto_uint64 load_3(const unsigned char *in)
+{
+  crypto_uint64 result;
+  result = (crypto_uint64) in[0];
+  result |= ((crypto_uint64) in[1]) << 8;
+  result |= ((crypto_uint64) in[2]) << 16;
+  return result;
+}
+
+static crypto_uint64 load_4(const unsigned char *in)
+{
+  crypto_uint64 result;
+  result = (crypto_uint64) in[0];
+  result |= ((crypto_uint64) in[1]) << 8;
+  result |= ((crypto_uint64) in[2]) << 16;
+  result |= ((crypto_uint64) in[3]) << 24;
+  return result;
+}
+
+/*
+Input:
+  a[0]+256*a[1]+...+256^31*a[31] = a
+  b[0]+256*b[1]+...+256^31*b[31] = b
+  c[0]+256*c[1]+...+256^31*c[31] = c
+
+Output:
+  s[0]+256*s[1]+...+256^31*s[31] = (ab+c) mod l
+  where l = 2^252 + 27742317777372353535851937790883648493.
+*/
+
+void sc_muladd(unsigned char *s,const unsigned char *a,const unsigned char *b,const unsigned char *c)
+{
+  crypto_int64 a0 = 2097151 & load_3(a);
+  crypto_int64 a1 = 2097151 & (load_4(a + 2) >> 5);
+  crypto_int64 a2 = 2097151 & (load_3(a + 5) >> 2);
+  crypto_int64 a3 = 2097151 & (load_4(a + 7) >> 7);
+  crypto_int64 a4 = 2097151 & (load_4(a + 10) >> 4);
+  crypto_int64 a5 = 2097151 & (load_3(a + 13) >> 1);
+  crypto_int64 a6 = 2097151 & (load_4(a + 15) >> 6);
+  crypto_int64 a7 = 2097151 & (load_3(a + 18) >> 3);
+  crypto_int64 a8 = 2097151 & load_3(a + 21);
+  crypto_int64 a9 = 2097151 & (load_4(a + 23) >> 5);
+  crypto_int64 a10 = 2097151 & (load_3(a + 26) >> 2);
+  crypto_int64 a11 = (load_4(a + 28) >> 7);
+  crypto_int64 b0 = 2097151 & load_3(b);
+  crypto_int64 b1 = 2097151 & (load_4(b + 2) >> 5);
+  crypto_int64 b2 = 2097151 & (load_3(b + 5) >> 2);
+  crypto_int64 b3 = 2097151 & (load_4(b + 7) >> 7);
+  crypto_int64 b4 = 2097151 & (load_4(b + 10) >> 4);
+  crypto_int64 b5 = 2097151 & (load_3(b + 13) >> 1);
+  crypto_int64 b6 = 2097151 & (load_4(b + 15) >> 6);
+  crypto_int64 b7 = 2097151 & (load_3(b + 18) >> 3);
+  crypto_int64 b8 = 2097151 & load_3(b + 21);
+  crypto_int64 b9 = 2097151 & (load_4(b + 23) >> 5);
+  crypto_int64 b10 = 2097151 & (load_3(b + 26) >> 2);
+  crypto_int64 b11 = (load_4(b + 28) >> 7);
+  crypto_int64 c0 = 2097151 & load_3(c);
+  crypto_int64 c1 = 2097151 & (load_4(c + 2) >> 5);
+  crypto_int64 c2 = 2097151 & (load_3(c + 5) >> 2);
+  crypto_int64 c3 = 2097151 & (load_4(c + 7) >> 7);
+  crypto_int64 c4 = 2097151 & (load_4(c + 10) >> 4);
+  crypto_int64 c5 = 2097151 & (load_3(c + 13) >> 1);
+  crypto_int64 c6 = 2097151 & (load_4(c + 15) >> 6);
+  crypto_int64 c7 = 2097151 & (load_3(c + 18) >> 3);
+  crypto_int64 c8 = 2097151 & load_3(c + 21);
+  crypto_int64 c9 = 2097151 & (load_4(c + 23) >> 5);
+  crypto_int64 c10 = 2097151 & (load_3(c + 26) >> 2);
+  crypto_int64 c11 = (load_4(c + 28) >> 7);
+  crypto_int64 s0;
+  crypto_int64 s1;
+  crypto_int64 s2;
+  crypto_int64 s3;
+  crypto_int64 s4;
+  crypto_int64 s5;
+  crypto_int64 s6;
+  crypto_int64 s7;
+  crypto_int64 s8;
+  crypto_int64 s9;
+  crypto_int64 s10;
+  crypto_int64 s11;
+  crypto_int64 s12;
+  crypto_int64 s13;
+  crypto_int64 s14;
+  crypto_int64 s15;
+  crypto_int64 s16;
+  crypto_int64 s17;
+  crypto_int64 s18;
+  crypto_int64 s19;
+  crypto_int64 s20;
+  crypto_int64 s21;
+  crypto_int64 s22;
+  crypto_int64 s23;
+  crypto_int64 carry0;
+  crypto_int64 carry1;
+  crypto_int64 carry2;
+  crypto_int64 carry3;
+  crypto_int64 carry4;
+  crypto_int64 carry5;
+  crypto_int64 carry6;
+  crypto_int64 carry7;
+  crypto_int64 carry8;
+  crypto_int64 carry9;
+  crypto_int64 carry10;
+  crypto_int64 carry11;
+  crypto_int64 carry12;
+  crypto_int64 carry13;
+  crypto_int64 carry14;
+  crypto_int64 carry15;
+  crypto_int64 carry16;
+  crypto_int64 carry17;
+  crypto_int64 carry18;
+  crypto_int64 carry19;
+  crypto_int64 carry20;
+  crypto_int64 carry21;
+  crypto_int64 carry22;
+
+  s0 = c0 + a0*b0;
+  s1 = c1 + a0*b1 + a1*b0;
+  s2 = c2 + a0*b2 + a1*b1 + a2*b0;
+  s3 = c3 + a0*b3 + a1*b2 + a2*b1 + a3*b0;
+  s4 = c4 + a0*b4 + a1*b3 + a2*b2 + a3*b1 + a4*b0;
+  s5 = c5 + a0*b5 + a1*b4 + a2*b3 + a3*b2 + a4*b1 + a5*b0;
+  s6 = c6 + a0*b6 + a1*b5 + a2*b4 + a3*b3 + a4*b2 + a5*b1 + a6*b0;
+  s7 = c7 + a0*b7 + a1*b6 + a2*b5 + a3*b4 + a4*b3 + a5*b2 + a6*b1 + a7*b0;
+  s8 = c8 + a0*b8 + a1*b7 + a2*b6 + a3*b5 + a4*b4 + a5*b3 + a6*b2 + a7*b1 + a8*b0;
+  s9 = c9 + a0*b9 + a1*b8 + a2*b7 + a3*b6 + a4*b5 + a5*b4 + a6*b3 + a7*b2 + a8*b1 + a9*b0;
+  s10 = c10 + a0*b10 + a1*b9 + a2*b8 + a3*b7 + a4*b6 + a5*b5 + a6*b4 + a7*b3 + a8*b2 + a9*b1 + a10*b0;
+  s11 = c11 + a0*b11 + a1*b10 + a2*b9 + a3*b8 + a4*b7 + a5*b6 + a6*b5 + a7*b4 + a8*b3 + a9*b2 + a10*b1 + a11*b0;
+  s12 = a1*b11 + a2*b10 + a3*b9 + a4*b8 + a5*b7 + a6*b6 + a7*b5 + a8*b4 + a9*b3 + a10*b2 + a11*b1;
+  s13 = a2*b11 + a3*b10 + a4*b9 + a5*b8 + a6*b7 + a7*b6 + a8*b5 + a9*b4 + a10*b3 + a11*b2;
+  s14 = a3*b11 + a4*b10 + a5*b9 + a6*b8 + a7*b7 + a8*b6 + a9*b5 + a10*b4 + a11*b3;
+  s15 = a4*b11 + a5*b10 + a6*b9 + a7*b8 + a8*b7 + a9*b6 + a10*b5 + a11*b4;
+  s16 = a5*b11 + a6*b10 + a7*b9 + a8*b8 + a9*b7 + a10*b6 + a11*b5;
+  s17 = a6*b11 + a7*b10 + a8*b9 + a9*b8 + a10*b7 + a11*b6;
+  s18 = a7*b11 + a8*b10 + a9*b9 + a10*b8 + a11*b7;
+  s19 = a8*b11 + a9*b10 + a10*b9 + a11*b8;
+  s20 = a9*b11 + a10*b10 + a11*b9;
+  s21 = a10*b11 + a11*b10;
+  s22 = a11*b11;
+  s23 = 0;
+
+  carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
+  carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
+  carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
+  carry18 = (s18 + (1<<20)) >> 21; s19 += carry18; s18 -= carry18 << 21;
+  carry20 = (s20 + (1<<20)) >> 21; s21 += carry20; s20 -= carry20 << 21;
+  carry22 = (s22 + (1<<20)) >> 21; s23 += carry22; s22 -= carry22 << 21;
+
+  carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+  carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
+  carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
+  carry17 = (s17 + (1<<20)) >> 21; s18 += carry17; s17 -= carry17 << 21;
+  carry19 = (s19 + (1<<20)) >> 21; s20 += carry19; s19 -= carry19 << 21;
+  carry21 = (s21 + (1<<20)) >> 21; s22 += carry21; s21 -= carry21 << 21;
+
+  s11 += s23 * 666643;
+  s12 += s23 * 470296;
+  s13 += s23 * 654183;
+  s14 -= s23 * 997805;
+  s15 += s23 * 136657;
+  s16 -= s23 * 683901;
+  s23 = 0;
+
+  s10 += s22 * 666643;
+  s11 += s22 * 470296;
+  s12 += s22 * 654183;
+  s13 -= s22 * 997805;
+  s14 += s22 * 136657;
+  s15 -= s22 * 683901;
+  s22 = 0;
+
+  s9 += s21 * 666643;
+  s10 += s21 * 470296;
+  s11 += s21 * 654183;
+  s12 -= s21 * 997805;
+  s13 += s21 * 136657;
+  s14 -= s21 * 683901;
+  s21 = 0;
+
+  s8 += s20 * 666643;
+  s9 += s20 * 470296;
+  s10 += s20 * 654183;
+  s11 -= s20 * 997805;
+  s12 += s20 * 136657;
+  s13 -= s20 * 683901;
+  s20 = 0;
+
+  s7 += s19 * 666643;
+  s8 += s19 * 470296;
+  s9 += s19 * 654183;
+  s10 -= s19 * 997805;
+  s11 += s19 * 136657;
+  s12 -= s19 * 683901;
+  s19 = 0;
+
+  s6 += s18 * 666643;
+  s7 += s18 * 470296;
+  s8 += s18 * 654183;
+  s9 -= s18 * 997805;
+  s10 += s18 * 136657;
+  s11 -= s18 * 683901;
+  s18 = 0;
+
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
+  carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
+  carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
+
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+  carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
+  carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
+
+  s5 += s17 * 666643;
+  s6 += s17 * 470296;
+  s7 += s17 * 654183;
+  s8 -= s17 * 997805;
+  s9 += s17 * 136657;
+  s10 -= s17 * 683901;
+  s17 = 0;
+
+  s4 += s16 * 666643;
+  s5 += s16 * 470296;
+  s6 += s16 * 654183;
+  s7 -= s16 * 997805;
+  s8 += s16 * 136657;
+  s9 -= s16 * 683901;
+  s16 = 0;
+
+  s3 += s15 * 666643;
+  s4 += s15 * 470296;
+  s5 += s15 * 654183;
+  s6 -= s15 * 997805;
+  s7 += s15 * 136657;
+  s8 -= s15 * 683901;
+  s15 = 0;
+
+  s2 += s14 * 666643;
+  s3 += s14 * 470296;
+  s4 += s14 * 654183;
+  s5 -= s14 * 997805;
+  s6 += s14 * 136657;
+  s7 -= s14 * 683901;
+  s14 = 0;
+
+  s1 += s13 * 666643;
+  s2 += s13 * 470296;
+  s3 += s13 * 654183;
+  s4 -= s13 * 997805;
+  s5 += s13 * 136657;
+  s6 -= s13 * 683901;
+  s13 = 0;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  s[0] = s0 >> 0;
+  s[1] = s0 >> 8;
+  s[2] = (s0 >> 16) | (s1 << 5);
+  s[3] = s1 >> 3;
+  s[4] = s1 >> 11;
+  s[5] = (s1 >> 19) | (s2 << 2);
+  s[6] = s2 >> 6;
+  s[7] = (s2 >> 14) | (s3 << 7);
+  s[8] = s3 >> 1;
+  s[9] = s3 >> 9;
+  s[10] = (s3 >> 17) | (s4 << 4);
+  s[11] = s4 >> 4;
+  s[12] = s4 >> 12;
+  s[13] = (s4 >> 20) | (s5 << 1);
+  s[14] = s5 >> 7;
+  s[15] = (s5 >> 15) | (s6 << 6);
+  s[16] = s6 >> 2;
+  s[17] = s6 >> 10;
+  s[18] = (s6 >> 18) | (s7 << 3);
+  s[19] = s7 >> 5;
+  s[20] = s7 >> 13;
+  s[21] = s8 >> 0;
+  s[22] = s8 >> 8;
+  s[23] = (s8 >> 16) | (s9 << 5);
+  s[24] = s9 >> 3;
+  s[25] = s9 >> 11;
+  s[26] = (s9 >> 19) | (s10 << 2);
+  s[27] = s10 >> 6;
+  s[28] = (s10 >> 14) | (s11 << 7);
+  s[29] = s11 >> 1;
+  s[30] = s11 >> 9;
+  s[31] = s11 >> 17;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sc_reduce.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sc_reduce.c
new file mode 100644
index 0000000000..d01f5a5737
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sc_reduce.c
@@ -0,0 +1,275 @@
+#include "sc.h"
+#include "crypto_int64.h"
+#include "crypto_uint32.h"
+#include "crypto_uint64.h"
+
+static crypto_uint64 load_3(const unsigned char *in)
+{
+  crypto_uint64 result;
+  result = (crypto_uint64) in[0];
+  result |= ((crypto_uint64) in[1]) << 8;
+  result |= ((crypto_uint64) in[2]) << 16;
+  return result;
+}
+
+static crypto_uint64 load_4(const unsigned char *in)
+{
+  crypto_uint64 result;
+  result = (crypto_uint64) in[0];
+  result |= ((crypto_uint64) in[1]) << 8;
+  result |= ((crypto_uint64) in[2]) << 16;
+  result |= ((crypto_uint64) in[3]) << 24;
+  return result;
+}
+
+/*
+Input:
+  s[0]+256*s[1]+...+256^63*s[63] = s
+
+Output:
+  s[0]+256*s[1]+...+256^31*s[31] = s mod l
+  where l = 2^252 + 27742317777372353535851937790883648493.
+  Overwrites s in place.
+*/
+
+void sc_reduce(unsigned char *s)
+{
+  crypto_int64 s0 = 2097151 & load_3(s);
+  crypto_int64 s1 = 2097151 & (load_4(s + 2) >> 5);
+  crypto_int64 s2 = 2097151 & (load_3(s + 5) >> 2);
+  crypto_int64 s3 = 2097151 & (load_4(s + 7) >> 7);
+  crypto_int64 s4 = 2097151 & (load_4(s + 10) >> 4);
+  crypto_int64 s5 = 2097151 & (load_3(s + 13) >> 1);
+  crypto_int64 s6 = 2097151 & (load_4(s + 15) >> 6);
+  crypto_int64 s7 = 2097151 & (load_3(s + 18) >> 3);
+  crypto_int64 s8 = 2097151 & load_3(s + 21);
+  crypto_int64 s9 = 2097151 & (load_4(s + 23) >> 5);
+  crypto_int64 s10 = 2097151 & (load_3(s + 26) >> 2);
+  crypto_int64 s11 = 2097151 & (load_4(s + 28) >> 7);
+  crypto_int64 s12 = 2097151 & (load_4(s + 31) >> 4);
+  crypto_int64 s13 = 2097151 & (load_3(s + 34) >> 1);
+  crypto_int64 s14 = 2097151 & (load_4(s + 36) >> 6);
+  crypto_int64 s15 = 2097151 & (load_3(s + 39) >> 3);
+  crypto_int64 s16 = 2097151 & load_3(s + 42);
+  crypto_int64 s17 = 2097151 & (load_4(s + 44) >> 5);
+  crypto_int64 s18 = 2097151 & (load_3(s + 47) >> 2);
+  crypto_int64 s19 = 2097151 & (load_4(s + 49) >> 7);
+  crypto_int64 s20 = 2097151 & (load_4(s + 52) >> 4);
+  crypto_int64 s21 = 2097151 & (load_3(s + 55) >> 1);
+  crypto_int64 s22 = 2097151 & (load_4(s + 57) >> 6);
+  crypto_int64 s23 = (load_4(s + 60) >> 3);
+  crypto_int64 carry0;
+  crypto_int64 carry1;
+  crypto_int64 carry2;
+  crypto_int64 carry3;
+  crypto_int64 carry4;
+  crypto_int64 carry5;
+  crypto_int64 carry6;
+  crypto_int64 carry7;
+  crypto_int64 carry8;
+  crypto_int64 carry9;
+  crypto_int64 carry10;
+  crypto_int64 carry11;
+  crypto_int64 carry12;
+  crypto_int64 carry13;
+  crypto_int64 carry14;
+  crypto_int64 carry15;
+  crypto_int64 carry16;
+
+  s11 += s23 * 666643;
+  s12 += s23 * 470296;
+  s13 += s23 * 654183;
+  s14 -= s23 * 997805;
+  s15 += s23 * 136657;
+  s16 -= s23 * 683901;
+  s23 = 0;
+
+  s10 += s22 * 666643;
+  s11 += s22 * 470296;
+  s12 += s22 * 654183;
+  s13 -= s22 * 997805;
+  s14 += s22 * 136657;
+  s15 -= s22 * 683901;
+  s22 = 0;
+
+  s9 += s21 * 666643;
+  s10 += s21 * 470296;
+  s11 += s21 * 654183;
+  s12 -= s21 * 997805;
+  s13 += s21 * 136657;
+  s14 -= s21 * 683901;
+  s21 = 0;
+
+  s8 += s20 * 666643;
+  s9 += s20 * 470296;
+  s10 += s20 * 654183;
+  s11 -= s20 * 997805;
+  s12 += s20 * 136657;
+  s13 -= s20 * 683901;
+  s20 = 0;
+
+  s7 += s19 * 666643;
+  s8 += s19 * 470296;
+  s9 += s19 * 654183;
+  s10 -= s19 * 997805;
+  s11 += s19 * 136657;
+  s12 -= s19 * 683901;
+  s19 = 0;
+
+  s6 += s18 * 666643;
+  s7 += s18 * 470296;
+  s8 += s18 * 654183;
+  s9 -= s18 * 997805;
+  s10 += s18 * 136657;
+  s11 -= s18 * 683901;
+  s18 = 0;
+
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
+  carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
+  carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
+
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+  carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
+  carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
+
+  s5 += s17 * 666643;
+  s6 += s17 * 470296;
+  s7 += s17 * 654183;
+  s8 -= s17 * 997805;
+  s9 += s17 * 136657;
+  s10 -= s17 * 683901;
+  s17 = 0;
+
+  s4 += s16 * 666643;
+  s5 += s16 * 470296;
+  s6 += s16 * 654183;
+  s7 -= s16 * 997805;
+  s8 += s16 * 136657;
+  s9 -= s16 * 683901;
+  s16 = 0;
+
+  s3 += s15 * 666643;
+  s4 += s15 * 470296;
+  s5 += s15 * 654183;
+  s6 -= s15 * 997805;
+  s7 += s15 * 136657;
+  s8 -= s15 * 683901;
+  s15 = 0;
+
+  s2 += s14 * 666643;
+  s3 += s14 * 470296;
+  s4 += s14 * 654183;
+  s5 -= s14 * 997805;
+  s6 += s14 * 136657;
+  s7 -= s14 * 683901;
+  s14 = 0;
+
+  s1 += s13 * 666643;
+  s2 += s13 * 470296;
+  s3 += s13 * 654183;
+  s4 -= s13 * 997805;
+  s5 += s13 * 136657;
+  s6 -= s13 * 683901;
+  s13 = 0;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  s[0] = s0 >> 0;
+  s[1] = s0 >> 8;
+  s[2] = (s0 >> 16) | (s1 << 5);
+  s[3] = s1 >> 3;
+  s[4] = s1 >> 11;
+  s[5] = (s1 >> 19) | (s2 << 2);
+  s[6] = s2 >> 6;
+  s[7] = (s2 >> 14) | (s3 << 7);
+  s[8] = s3 >> 1;
+  s[9] = s3 >> 9;
+  s[10] = (s3 >> 17) | (s4 << 4);
+  s[11] = s4 >> 4;
+  s[12] = s4 >> 12;
+  s[13] = (s4 >> 20) | (s5 << 1);
+  s[14] = s5 >> 7;
+  s[15] = (s5 >> 15) | (s6 << 6);
+  s[16] = s6 >> 2;
+  s[17] = s6 >> 10;
+  s[18] = (s6 >> 18) | (s7 << 3);
+  s[19] = s7 >> 5;
+  s[20] = s7 >> 13;
+  s[21] = s8 >> 0;
+  s[22] = s8 >> 8;
+  s[23] = (s8 >> 16) | (s9 << 5);
+  s[24] = s9 >> 3;
+  s[25] = s9 >> 11;
+  s[26] = (s9 >> 19) | (s10 << 2);
+  s[27] = s10 >> 6;
+  s[28] = (s10 >> 14) | (s11 << 7);
+  s[29] = s11 >> 1;
+  s[30] = s11 >> 9;
+  s[31] = s11 >> 17;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sc_sub.xmr.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sc_sub.xmr.c
new file mode 100644
index 0000000000..cd4a50ff00
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sc_sub.xmr.c
@@ -0,0 +1,504 @@
+/*
+ * sc_sub, sc_mulsub, sc_mul
+ * 
+ * (These are from the old code as well)
+ */
+
+
+#include "sc.h"
+#include "crypto_int64.h"
+#include "crypto_uint32.h"
+#include "crypto_uint64.h"
+
+static crypto_uint64 load_3(const unsigned char *in)
+{
+  crypto_uint64 result;
+  result = (crypto_uint64) in[0];
+  result |= ((crypto_uint64) in[1]) << 8;
+  result |= ((crypto_uint64) in[2]) << 16;
+  return result;
+}
+
+static crypto_uint64 load_4(const unsigned char *in)
+{
+  crypto_uint64 result;
+  result = (crypto_uint64) in[0];
+  result |= ((crypto_uint64) in[1]) << 8;
+  result |= ((crypto_uint64) in[2]) << 16;
+  result |= ((crypto_uint64) in[3]) << 24;
+  return result;
+}
+
+void sc_sub(unsigned char *s, const unsigned char *a, const unsigned char *b) {
+  int64_t a0 = 2097151 & load_3(a);
+  int64_t a1 = 2097151 & (load_4(a + 2) >> 5);
+  int64_t a2 = 2097151 & (load_3(a + 5) >> 2);
+  int64_t a3 = 2097151 & (load_4(a + 7) >> 7);
+  int64_t a4 = 2097151 & (load_4(a + 10) >> 4);
+  int64_t a5 = 2097151 & (load_3(a + 13) >> 1);
+  int64_t a6 = 2097151 & (load_4(a + 15) >> 6);
+  int64_t a7 = 2097151 & (load_3(a + 18) >> 3);
+  int64_t a8 = 2097151 & load_3(a + 21);
+  int64_t a9 = 2097151 & (load_4(a + 23) >> 5);
+  int64_t a10 = 2097151 & (load_3(a + 26) >> 2);
+  int64_t a11 = (load_4(a + 28) >> 7);
+  int64_t b0 = 2097151 & load_3(b);
+  int64_t b1 = 2097151 & (load_4(b + 2) >> 5);
+  int64_t b2 = 2097151 & (load_3(b + 5) >> 2);
+  int64_t b3 = 2097151 & (load_4(b + 7) >> 7);
+  int64_t b4 = 2097151 & (load_4(b + 10) >> 4);
+  int64_t b5 = 2097151 & (load_3(b + 13) >> 1);
+  int64_t b6 = 2097151 & (load_4(b + 15) >> 6);
+  int64_t b7 = 2097151 & (load_3(b + 18) >> 3);
+  int64_t b8 = 2097151 & load_3(b + 21);
+  int64_t b9 = 2097151 & (load_4(b + 23) >> 5);
+  int64_t b10 = 2097151 & (load_3(b + 26) >> 2);
+  int64_t b11 = (load_4(b + 28) >> 7);
+  int64_t s0 = a0 - b0;
+  int64_t s1 = a1 - b1;
+  int64_t s2 = a2 - b2;
+  int64_t s3 = a3 - b3;
+  int64_t s4 = a4 - b4;
+  int64_t s5 = a5 - b5;
+  int64_t s6 = a6 - b6;
+  int64_t s7 = a7 - b7;
+  int64_t s8 = a8 - b8;
+  int64_t s9 = a9 - b9;
+  int64_t s10 = a10 - b10;
+  int64_t s11 = a11 - b11;
+  int64_t s12 = 0;
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+  int64_t carry10;
+  int64_t carry11;
+
+  carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  s[0] = s0 >> 0;
+  s[1] = s0 >> 8;
+  s[2] = (s0 >> 16) | (s1 << 5);
+  s[3] = s1 >> 3;
+  s[4] = s1 >> 11;
+  s[5] = (s1 >> 19) | (s2 << 2);
+  s[6] = s2 >> 6;
+  s[7] = (s2 >> 14) | (s3 << 7);
+  s[8] = s3 >> 1;
+  s[9] = s3 >> 9;
+  s[10] = (s3 >> 17) | (s4 << 4);
+  s[11] = s4 >> 4;
+  s[12] = s4 >> 12;
+  s[13] = (s4 >> 20) | (s5 << 1);
+  s[14] = s5 >> 7;
+  s[15] = (s5 >> 15) | (s6 << 6);
+  s[16] = s6 >> 2;
+  s[17] = s6 >> 10;
+  s[18] = (s6 >> 18) | (s7 << 3);
+  s[19] = s7 >> 5;
+  s[20] = s7 >> 13;
+  s[21] = s8 >> 0;
+  s[22] = s8 >> 8;
+  s[23] = (s8 >> 16) | (s9 << 5);
+  s[24] = s9 >> 3;
+  s[25] = s9 >> 11;
+  s[26] = (s9 >> 19) | (s10 << 2);
+  s[27] = s10 >> 6;
+  s[28] = (s10 >> 14) | (s11 << 7);
+  s[29] = s11 >> 1;
+  s[30] = s11 >> 9;
+  s[31] = s11 >> 17;
+}
+
+/*
+Input:
+  a[0]+256*a[1]+...+256^31*a[31] = a
+  b[0]+256*b[1]+...+256^31*b[31] = b
+  c[0]+256*c[1]+...+256^31*c[31] = c
+
+Output:
+  s[0]+256*s[1]+...+256^31*s[31] = (c-ab) mod l
+  where l = 2^252 + 27742317777372353535851937790883648493.
+*/
+
+//x
+void sc_mulsub(unsigned char *s, const unsigned char *a, const unsigned char *b, const unsigned char *c) {
+  int64_t a0 = 2097151 & load_3(a);
+  int64_t a1 = 2097151 & (load_4(a + 2) >> 5);
+  int64_t a2 = 2097151 & (load_3(a + 5) >> 2);
+  int64_t a3 = 2097151 & (load_4(a + 7) >> 7);
+  int64_t a4 = 2097151 & (load_4(a + 10) >> 4);
+  int64_t a5 = 2097151 & (load_3(a + 13) >> 1);
+  int64_t a6 = 2097151 & (load_4(a + 15) >> 6);
+  int64_t a7 = 2097151 & (load_3(a + 18) >> 3);
+  int64_t a8 = 2097151 & load_3(a + 21);
+  int64_t a9 = 2097151 & (load_4(a + 23) >> 5);
+  int64_t a10 = 2097151 & (load_3(a + 26) >> 2);
+  int64_t a11 = (load_4(a + 28) >> 7);
+  int64_t b0 = 2097151 & load_3(b);
+  int64_t b1 = 2097151 & (load_4(b + 2) >> 5);
+  int64_t b2 = 2097151 & (load_3(b + 5) >> 2);
+  int64_t b3 = 2097151 & (load_4(b + 7) >> 7);
+  int64_t b4 = 2097151 & (load_4(b + 10) >> 4);
+  int64_t b5 = 2097151 & (load_3(b + 13) >> 1);
+  int64_t b6 = 2097151 & (load_4(b + 15) >> 6);
+  int64_t b7 = 2097151 & (load_3(b + 18) >> 3);
+  int64_t b8 = 2097151 & load_3(b + 21);
+  int64_t b9 = 2097151 & (load_4(b + 23) >> 5);
+  int64_t b10 = 2097151 & (load_3(b + 26) >> 2);
+  int64_t b11 = (load_4(b + 28) >> 7);
+  int64_t c0 = 2097151 & load_3(c);
+  int64_t c1 = 2097151 & (load_4(c + 2) >> 5);
+  int64_t c2 = 2097151 & (load_3(c + 5) >> 2);
+  int64_t c3 = 2097151 & (load_4(c + 7) >> 7);
+  int64_t c4 = 2097151 & (load_4(c + 10) >> 4);
+  int64_t c5 = 2097151 & (load_3(c + 13) >> 1);
+  int64_t c6 = 2097151 & (load_4(c + 15) >> 6);
+  int64_t c7 = 2097151 & (load_3(c + 18) >> 3);
+  int64_t c8 = 2097151 & load_3(c + 21);
+  int64_t c9 = 2097151 & (load_4(c + 23) >> 5);
+  int64_t c10 = 2097151 & (load_3(c + 26) >> 2);
+  int64_t c11 = (load_4(c + 28) >> 7);
+  int64_t s0;
+  int64_t s1;
+  int64_t s2;
+  int64_t s3;
+  int64_t s4;
+  int64_t s5;
+  int64_t s6;
+  int64_t s7;
+  int64_t s8;
+  int64_t s9;
+  int64_t s10;
+  int64_t s11;
+  int64_t s12;
+  int64_t s13;
+  int64_t s14;
+  int64_t s15;
+  int64_t s16;
+  int64_t s17;
+  int64_t s18;
+  int64_t s19;
+  int64_t s20;
+  int64_t s21;
+  int64_t s22;
+  int64_t s23;
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+  int64_t carry10;
+  int64_t carry11;
+  int64_t carry12;
+  int64_t carry13;
+  int64_t carry14;
+  int64_t carry15;
+  int64_t carry16;
+  int64_t carry17;
+  int64_t carry18;
+  int64_t carry19;
+  int64_t carry20;
+  int64_t carry21;
+  int64_t carry22;
+
+  s0 = c0 - a0*b0;
+  s1 = c1 - (a0*b1 + a1*b0);
+  s2 = c2 - (a0*b2 + a1*b1 + a2*b0);
+  s3 = c3 - (a0*b3 + a1*b2 + a2*b1 + a3*b0);
+  s4 = c4 - (a0*b4 + a1*b3 + a2*b2 + a3*b1 + a4*b0);
+  s5 = c5 - (a0*b5 + a1*b4 + a2*b3 + a3*b2 + a4*b1 + a5*b0);
+  s6 = c6 - (a0*b6 + a1*b5 + a2*b4 + a3*b3 + a4*b2 + a5*b1 + a6*b0);
+  s7 = c7 - (a0*b7 + a1*b6 + a2*b5 + a3*b4 + a4*b3 + a5*b2 + a6*b1 + a7*b0);
+  s8 = c8 - (a0*b8 + a1*b7 + a2*b6 + a3*b5 + a4*b4 + a5*b3 + a6*b2 + a7*b1 + a8*b0);
+  s9 = c9 - (a0*b9 + a1*b8 + a2*b7 + a3*b6 + a4*b5 + a5*b4 + a6*b3 + a7*b2 + a8*b1 + a9*b0);
+  s10 = c10 - (a0*b10 + a1*b9 + a2*b8 + a3*b7 + a4*b6 + a5*b5 + a6*b4 + a7*b3 + a8*b2 + a9*b1 + a10*b0);
+  s11 = c11 - (a0*b11 + a1*b10 + a2*b9 + a3*b8 + a4*b7 + a5*b6 + a6*b5 + a7*b4 + a8*b3 + a9*b2 + a10*b1 + a11*b0);
+  s12 = -(a1*b11 + a2*b10 + a3*b9 + a4*b8 + a5*b7 + a6*b6 + a7*b5 + a8*b4 + a9*b3 + a10*b2 + a11*b1);
+  s13 = -(a2*b11 + a3*b10 + a4*b9 + a5*b8 + a6*b7 + a7*b6 + a8*b5 + a9*b4 + a10*b3 + a11*b2);
+  s14 = -(a3*b11 + a4*b10 + a5*b9 + a6*b8 + a7*b7 + a8*b6 + a9*b5 + a10*b4 + a11*b3);
+  s15 = -(a4*b11 + a5*b10 + a6*b9 + a7*b8 + a8*b7 + a9*b6 + a10*b5 + a11*b4);
+  s16 = -(a5*b11 + a6*b10 + a7*b9 + a8*b8 + a9*b7 + a10*b6 + a11*b5);
+  s17 = -(a6*b11 + a7*b10 + a8*b9 + a9*b8 + a10*b7 + a11*b6);
+  s18 = -(a7*b11 + a8*b10 + a9*b9 + a10*b8 + a11*b7);
+  s19 = -(a8*b11 + a9*b10 + a10*b9 + a11*b8);
+  s20 = -(a9*b11 + a10*b10 + a11*b9);
+  s21 = -(a10*b11 + a11*b10);
+  s22 = -a11*b11;
+  s23 = 0;
+
+  carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
+  carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
+  carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
+  carry18 = (s18 + (1<<20)) >> 21; s19 += carry18; s18 -= carry18 << 21;
+  carry20 = (s20 + (1<<20)) >> 21; s21 += carry20; s20 -= carry20 << 21;
+  carry22 = (s22 + (1<<20)) >> 21; s23 += carry22; s22 -= carry22 << 21;
+
+  carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+  carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
+  carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
+  carry17 = (s17 + (1<<20)) >> 21; s18 += carry17; s17 -= carry17 << 21;
+  carry19 = (s19 + (1<<20)) >> 21; s20 += carry19; s19 -= carry19 << 21;
+  carry21 = (s21 + (1<<20)) >> 21; s22 += carry21; s21 -= carry21 << 21;
+
+  s11 += s23 * 666643;
+  s12 += s23 * 470296;
+  s13 += s23 * 654183;
+  s14 -= s23 * 997805;
+  s15 += s23 * 136657;
+  s16 -= s23 * 683901;
+
+  s10 += s22 * 666643;
+  s11 += s22 * 470296;
+  s12 += s22 * 654183;
+  s13 -= s22 * 997805;
+  s14 += s22 * 136657;
+  s15 -= s22 * 683901;
+
+  s9 += s21 * 666643;
+  s10 += s21 * 470296;
+  s11 += s21 * 654183;
+  s12 -= s21 * 997805;
+  s13 += s21 * 136657;
+  s14 -= s21 * 683901;
+
+  s8 += s20 * 666643;
+  s9 += s20 * 470296;
+  s10 += s20 * 654183;
+  s11 -= s20 * 997805;
+  s12 += s20 * 136657;
+  s13 -= s20 * 683901;
+
+  s7 += s19 * 666643;
+  s8 += s19 * 470296;
+  s9 += s19 * 654183;
+  s10 -= s19 * 997805;
+  s11 += s19 * 136657;
+  s12 -= s19 * 683901;
+
+  s6 += s18 * 666643;
+  s7 += s18 * 470296;
+  s8 += s18 * 654183;
+  s9 -= s18 * 997805;
+  s10 += s18 * 136657;
+  s11 -= s18 * 683901;
+
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
+  carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
+  carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
+
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+  carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
+  carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
+
+  s5 += s17 * 666643;
+  s6 += s17 * 470296;
+  s7 += s17 * 654183;
+  s8 -= s17 * 997805;
+  s9 += s17 * 136657;
+  s10 -= s17 * 683901;
+
+  s4 += s16 * 666643;
+  s5 += s16 * 470296;
+  s6 += s16 * 654183;
+  s7 -= s16 * 997805;
+  s8 += s16 * 136657;
+  s9 -= s16 * 683901;
+
+  s3 += s15 * 666643;
+  s4 += s15 * 470296;
+  s5 += s15 * 654183;
+  s6 -= s15 * 997805;
+  s7 += s15 * 136657;
+  s8 -= s15 * 683901;
+
+  s2 += s14 * 666643;
+  s3 += s14 * 470296;
+  s4 += s14 * 654183;
+  s5 -= s14 * 997805;
+  s6 += s14 * 136657;
+  s7 -= s14 * 683901;
+
+  s1 += s13 * 666643;
+  s2 += s13 * 470296;
+  s3 += s13 * 654183;
+  s4 -= s13 * 997805;
+  s5 += s13 * 136657;
+  s6 -= s13 * 683901;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  s[0] = s0 >> 0;
+  s[1] = s0 >> 8;
+  s[2] = (s0 >> 16) | (s1 << 5);
+  s[3] = s1 >> 3;
+  s[4] = s1 >> 11;
+  s[5] = (s1 >> 19) | (s2 << 2);
+  s[6] = s2 >> 6;
+  s[7] = (s2 >> 14) | (s3 << 7);
+  s[8] = s3 >> 1;
+  s[9] = s3 >> 9;
+  s[10] = (s3 >> 17) | (s4 << 4);
+  s[11] = s4 >> 4;
+  s[12] = s4 >> 12;
+  s[13] = (s4 >> 20) | (s5 << 1);
+  s[14] = s5 >> 7;
+  s[15] = (s5 >> 15) | (s6 << 6);
+  s[16] = s6 >> 2;
+  s[17] = s6 >> 10;
+  s[18] = (s6 >> 18) | (s7 << 3);
+  s[19] = s7 >> 5;
+  s[20] = s7 >> 13;
+  s[21] = s8 >> 0;
+  s[22] = s8 >> 8;
+  s[23] = (s8 >> 16) | (s9 << 5);
+  s[24] = s9 >> 3;
+  s[25] = s9 >> 11;
+  s[26] = (s9 >> 19) | (s10 << 2);
+  s[27] = s10 >> 6;
+  s[28] = (s10 >> 14) | (s11 << 7);
+  s[29] = s11 >> 1;
+  s[30] = s11 >> 9;
+  s[31] = s11 >> 17;
+}
+
+
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/scrap.txt b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/scrap.txt
new file mode 100644
index 0000000000..9a02605dbf
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/scrap.txt
@@ -0,0 +1,53 @@
+#include "ge.h"
+
+/*
+r = p + q
+*/
+
+void ge_add(ge_p1p1 *r,const ge_p3 *p,const ge_cached *q)
+{
+  fe t0;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+fe_add(r->X,p->Y,p->X);
+
+fe_sub(r->Y,p->Y,p->X);
+
+fe_mul(r->Z,r->X,q->YplusX);
+
+fe_mul(r->Y,r->Y,q->YminusX);
+
+fe_mul(r->T,q->T2d,p->T);
+
+fe_mul(r->X,p->Z,q->Z);
+
+fe_add(t0,r->X,r->X);
+
+fe_sub(r->X,r->Z,r->Y);
+
+fe_add(r->Y,r->Z,r->Y);
+
+fe_add(r->Z,t0,r->T);
+
+fe_sub(r->T,t0,r->T);
+
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sign.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sign.c
new file mode 100644
index 0000000000..de53742a6c
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sign.c
@@ -0,0 +1,41 @@
+#include <string.h>
+#include "crypto_sign.h"
+#include "crypto_hash_sha512.h"
+#include "ge.h"
+#include "sc.h"
+
+int crypto_sign(
+  unsigned char *sm,unsigned long long *smlen,
+  const unsigned char *m,unsigned long long mlen,
+  const unsigned char *sk
+)
+{
+  unsigned char pk[32];
+  unsigned char az[64];
+  unsigned char nonce[64];
+  unsigned char hram[64];
+  ge_p3 R;
+
+  memmove(pk,sk + 32,32);
+
+  crypto_hash_sha512(az,sk,32);
+  az[0] &= 248;
+  az[31] &= 63;
+  az[31] |= 64;
+
+  *smlen = mlen + 64;
+  memmove(sm + 64,m,mlen);
+  memmove(sm + 32,az + 32,32);
+  crypto_hash_sha512(nonce,sm + 32,mlen + 32);
+  memmove(sm + 32,pk,32);
+
+  sc_reduce(nonce);
+  ge_scalarmult_base(&R,nonce);
+  ge_p3_tobytes(sm,&R);
+
+  crypto_hash_sha512(hram,sm,mlen + 64);
+  sc_reduce(hram);
+  sc_muladd(sm + 32,hram,az,nonce);
+
+  return 0;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sqrtm1.h b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sqrtm1.h
new file mode 100644
index 0000000000..d8caa23b6a
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sqrtm1.h
@@ -0,0 +1 @@
+-32595792,-7943725,9377950,3500415,12389472,-272473,-25146209,-2005654,326686,11406482
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sqrtm1.py b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sqrtm1.py
new file mode 100644
index 0000000000..9a47fbc12a
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sqrtm1.py
@@ -0,0 +1,28 @@
+q = 2**255 - 19
+
+def expmod(b,e,m):
+  if e == 0: return 1
+  t = expmod(b,e/2,m)**2 % m
+  if e & 1: t = (t*b) % m
+  return t
+
+def inv(x):
+  return expmod(x,q-2,q)
+
+def radix255(x):
+  x = x % q
+  if x + x > q: x -= q
+  x = [x,0,0,0,0,0,0,0,0,0]
+  bits = [26,25,26,25,26,25,26,25,26,25]
+  for i in range(9):
+    carry = (x[i] + 2**(bits[i]-1)) / 2**bits[i]
+    x[i] -= carry * 2**bits[i]
+    x[i + 1] += carry
+  result = ""
+  for i in range(9):
+    result = result+str(x[i])+","
+  result = result+str(x[9])
+  return result
+
+I = expmod(2,(q-1)/4,q)
+print radix255(I)
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/test.py b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/test.py
new file mode 100644
index 0000000000..10fa408ceb
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/test.py
@@ -0,0 +1,5 @@
+import os
+l = "(((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;"
+
+os.system("sed -i 's/crypto_verify_32(s, zero)/"+l+"/' crypto-ops.c")
+
diff --git a/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/xmrSpecificOld.c b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/xmrSpecificOld.c
new file mode 100644
index 0000000000..e6567c1200
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/ref10CommentedCombined/xmrSpecificOld.c
@@ -0,0 +1,776 @@
+/*Code inherited from the original cryptonote (I didn't write these) */
+/*These functions either don't exist in, or are modified from ref10*/
+
+
+/* From fe_isnonzero.c, modified */
+
+//x
+static int fe_isnonzero(const fe f) {
+  unsigned char s[32];
+  fe_tobytes(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;
+}
+
+//double scalar mult precomp
+void ge_dsm_precomp(ge_dsmp r, const ge_p3 *s) {
+  ge_p1p1 t;
+  ge_p3 s2, u;
+  ge_p3_to_cached(&r[0], s);
+  ge_p3_dbl(&t, s); ge_p1p1_to_p3(&s2, &t);
+  ge_add(&t, &s2, &r[0]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&r[1], &u);
+  ge_add(&t, &s2, &r[1]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&r[2], &u);
+  ge_add(&t, &s2, &r[2]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&r[3], &u);
+  ge_add(&t, &s2, &r[3]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&r[4], &u);
+  ge_add(&t, &s2, &r[4]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&r[5], &u);
+  ge_add(&t, &s2, &r[5]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&r[6], &u);
+  ge_add(&t, &s2, &r[6]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&r[7], &u);
+}
+
+/*
+r = a * A + b * B
+where a = a[0]+256*a[1]+...+256^31 a[31].
+and b = b[0]+256*b[1]+...+256^31 b[31].
+B is the Ed25519 base point (x,4/5) with x positive.
+*/
+
+void ge_double_scalarmult_base_vartime(ge_p2 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b) {
+  signed char aslide[256];
+  signed char bslide[256];
+  ge_dsmp Ai; /* A, 3A, 5A, 7A, 9A, 11A, 13A, 15A */
+  ge_p1p1 t;
+  ge_p3 u;
+  int i;
+
+  slide(aslide, a);
+  slide(bslide, b);
+  ge_dsm_precomp(Ai, A);/* A, 3A, 5A, 7A, 9A, 11A, 13A, 15A */
+
+  ge_p2_0(r);
+
+  for (i = 255; i >= 0; --i) {
+      //so this gets us to the highest i such that both have a nonzero
+    if (aslide[i] || bslide[i]) break;
+  }
+
+  for (; i >= 0; --i) {
+    ge_p2_dbl(&t, r);//simple double and add
+
+    if (aslide[i] > 0) {
+      ge_p1p1_to_p3(&u, &t);
+      ge_add(&t, &u, &Ai[aslide[i]/2]);
+    } else if (aslide[i] < 0) {
+      ge_p1p1_to_p3(&u, &t);
+      ge_sub(&t, &u, &Ai[(-aslide[i])/2]);
+    }
+
+    if (bslide[i] > 0) {
+      ge_p1p1_to_p3(&u, &t);
+      ge_madd(&t, &u, &ge_Bi[bslide[i]/2]);
+    } else if (bslide[i] < 0) {
+      ge_p1p1_to_p3(&u, &t);
+      ge_msub(&t, &u, &ge_Bi[(-bslide[i])/2]);
+    }
+
+    ge_p1p1_to_p2(r, &t);
+  }
+}
+
+
+/* From ge_frombytes.c, modified */
+//this is like xrecover .. 
+//x
+int ge_frombytes_vartime(ge_p3 *h, const unsigned char *s) {
+  fe u;
+  fe v;
+  fe vxx;
+  fe check;
+
+  /* From fe_frombytes.c */
+
+  int64_t h0 = load_4(s);
+  int64_t h1 = load_3(s + 4) << 6;
+  int64_t h2 = load_3(s + 7) << 5;
+  int64_t h3 = load_3(s + 10) << 3;
+  int64_t h4 = load_3(s + 13) << 2;
+  int64_t h5 = load_4(s + 16);
+  int64_t h6 = load_3(s + 20) << 7;
+  int64_t h7 = load_3(s + 23) << 5;
+  int64_t h8 = load_3(s + 26) << 4;
+  int64_t h9 = (load_3(s + 29) & 8388607) << 2;
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+
+  /* Validate the number to be canonical */
+  if (h9 == 33554428 && h8 == 268435440 && h7 == 536870880 && h6 == 2147483520 &&
+    h5 == 4294967295 && h4 == 67108860 && h3 == 134217720 && h2 == 536870880 &&
+    h1 == 1073741760 && h0 >= 4294967277) {
+    return -1;
+  }
+
+  carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+  carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+  carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+  carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+  carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+  carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+  carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+  carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+  carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+  carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+  h->Y[0] = h0;
+  h->Y[1] = h1;
+  h->Y[2] = h2;
+  h->Y[3] = h3;
+  h->Y[4] = h4;
+  h->Y[5] = h5;
+  h->Y[6] = h6;
+  h->Y[7] = h7;
+  h->Y[8] = h8;
+  h->Y[9] = h9;
+
+  /* End fe_frombytes.c */
+
+  fe_1(h->Z);
+  fe_sq(u, h->Y);
+  fe_mul(v, u, fe_d);
+  fe_sub(u, u, h->Z);       /* u = y^2-1 */
+  fe_add(v, v, h->Z);       /* v = dy^2+1 */
+
+  fe_divpowm1(h->X, u, v); /* x = uv^3(uv^7)^((q-5)/8) */
+
+  fe_sq(vxx, h->X);
+  fe_mul(vxx, vxx, v);
+  fe_sub(check, vxx, u);    /* vx^2-u */
+  if (fe_isnonzero(check)) {
+    fe_add(check, vxx, u);  /* vx^2+u */
+    if (fe_isnonzero(check)) {
+      return -1;
+    }
+    fe_mul(h->X, h->X, fe_sqrtm1); //this is mapping X to X * sqrt(-1) c.f. 3.1 in hisil, dong, etc. 
+  }
+
+  if (fe_isnegative(h->X) != (s[31] >> 7)) {
+    /* If x = 0, the sign must be positive */
+    if (!fe_isnonzero(h->X)) {
+      return -1;
+    }
+    fe_neg(h->X, h->X);
+  }
+
+  fe_mul(h->T, h->X, h->Y);
+  return 0;
+}
+
+/* New code */
+/* (u / v)^(m + 1) */
+static void fe_divpowm1(fe r, const fe u, const fe v) {
+  fe v3, uv7, t0, t1, t2;
+  int i;
+
+  fe_sq(v3, v);
+  fe_mul(v3, v3, v); /* v3 = v^3 */
+  fe_sq(uv7, v3);
+  fe_mul(uv7, uv7, v);
+  fe_mul(uv7, uv7, u); /* uv7 = uv^7 */
+
+  /*fe_pow22523(uv7, uv7);*/
+
+  /* From fe_pow22523.c */
+
+  fe_sq(t0, uv7);
+  fe_sq(t1, t0);
+  fe_sq(t1, t1);
+  fe_mul(t1, uv7, t1);
+  fe_mul(t0, t0, t1);
+  fe_sq(t0, t0);
+  fe_mul(t0, t1, t0);
+  fe_sq(t1, t0);
+  for (i = 0; i < 4; ++i) {
+    fe_sq(t1, t1);
+  }
+  fe_mul(t0, t1, t0);
+  fe_sq(t1, t0);
+  for (i = 0; i < 9; ++i) {
+    fe_sq(t1, t1);
+  }
+  fe_mul(t1, t1, t0);
+  fe_sq(t2, t1);
+  for (i = 0; i < 19; ++i) {
+    fe_sq(t2, t2);
+  }
+  fe_mul(t1, t2, t1);
+  for (i = 0; i < 10; ++i) {
+    fe_sq(t1, t1);
+  }
+  fe_mul(t0, t1, t0);
+  fe_sq(t1, t0);
+  for (i = 0; i < 49; ++i) {
+    fe_sq(t1, t1);
+  }
+  fe_mul(t1, t1, t0);
+  fe_sq(t2, t1);
+  for (i = 0; i < 99; ++i) {
+    fe_sq(t2, t2);
+  }
+  fe_mul(t1, t2, t1);
+  for (i = 0; i < 50; ++i) {
+    fe_sq(t1, t1);
+  }
+  fe_mul(t0, t1, t0);
+  fe_sq(t0, t0);
+  fe_sq(t0, t0);
+  fe_mul(t0, t0, uv7);
+
+  /* End fe_pow22523.c */
+  /* t0 = (uv^7)^((q-5)/8) */
+  fe_mul(t0, t0, v3);
+  fe_mul(r, t0, u); /* u^(m+1)v^(-(m+1)) */
+}
+
+static void ge_cached_0(ge_cached *r) {
+  fe_1(r->YplusX);
+  fe_1(r->YminusX);
+  fe_1(r->Z);
+  fe_0(r->T2d);
+}
+
+static void ge_cached_cmov(ge_cached *t, const ge_cached *u, unsigned char b) {
+  fe_cmov(t->YplusX, u->YplusX, b);
+  fe_cmov(t->YminusX, u->YminusX, b);
+  fe_cmov(t->Z, u->Z, b);
+  fe_cmov(t->T2d, u->T2d, b);
+}
+
+/* Assumes that a[31] <= 127 */
+void ge_scalarmult(ge_p2 *r, const unsigned char *a, const ge_p3 *A) {
+  signed char e[64];
+  int carry, carry2, i;
+  ge_cached Ai[8]; /* 1 * A, 2 * A, ..., 8 * A */
+  ge_p1p1 t;
+  ge_p3 u;
+
+  carry = 0; /* 0..1 */
+  for (i = 0; i < 31; i++) {
+    carry += a[i]; /* 0..256 */
+    carry2 = (carry + 8) >> 4; /* 0..16 */
+    e[2 * i] = carry - (carry2 << 4); /* -8..7 */
+    carry = (carry2 + 8) >> 4; /* 0..1 */
+    e[2 * i + 1] = carry2 - (carry << 4); /* -8..7 */
+  }
+  carry += a[31]; /* 0..128 */
+  carry2 = (carry + 8) >> 4; /* 0..8 */
+  e[62] = carry - (carry2 << 4); /* -8..7 */
+  e[63] = carry2; /* 0..8 */
+
+  ge_p3_to_cached(&Ai[0], A);
+  for (i = 0; i < 7; i++) {
+    ge_add(&t, A, &Ai[i]);
+    ge_p1p1_to_p3(&u, &t);
+    ge_p3_to_cached(&Ai[i + 1], &u);
+  }
+
+  ge_p2_0(r);
+  for (i = 63; i >= 0; i--) {
+    signed char b = e[i];
+    unsigned char bnegative = negative(b);
+    unsigned char babs = b - (((-bnegative) & b) << 1);
+    ge_cached cur, minuscur;
+    ge_p2_dbl(&t, r);
+    ge_p1p1_to_p2(r, &t);
+    ge_p2_dbl(&t, r);
+    ge_p1p1_to_p2(r, &t);
+    ge_p2_dbl(&t, r);
+    ge_p1p1_to_p2(r, &t);
+    ge_p2_dbl(&t, r);
+    ge_p1p1_to_p3(&u, &t);
+    ge_cached_0(&cur);
+    ge_cached_cmov(&cur, &Ai[0], equal(babs, 1));
+    ge_cached_cmov(&cur, &Ai[1], equal(babs, 2));
+    ge_cached_cmov(&cur, &Ai[2], equal(babs, 3));
+    ge_cached_cmov(&cur, &Ai[3], equal(babs, 4));
+    ge_cached_cmov(&cur, &Ai[4], equal(babs, 5));
+    ge_cached_cmov(&cur, &Ai[5], equal(babs, 6));
+    ge_cached_cmov(&cur, &Ai[6], equal(babs, 7));
+    ge_cached_cmov(&cur, &Ai[7], equal(babs, 8));
+    fe_copy(minuscur.YplusX, cur.YminusX);
+    fe_copy(minuscur.YminusX, cur.YplusX);
+    fe_copy(minuscur.Z, cur.Z);
+    fe_neg(minuscur.T2d, cur.T2d);
+    ge_cached_cmov(&cur, &minuscur, bnegative);
+    ge_add(&t, &u, &cur);
+    ge_p1p1_to_p2(r, &t);
+  }
+}
+
+//assume Bi has precomputed multiples
+void ge_double_scalarmult_precomp_vartime(ge_p2 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b, const ge_dsmp Bii) {
+  signed char aslide[256];
+  signed char bslide[256];
+  ge_dsmp Ai; /* A, 3A, 5A, 7A, 9A, 11A, 13A, 15A */ //precomps
+  ge_p1p1 t;
+  ge_p3 u;
+  int i;
+
+  slide(aslide, a);
+  slide(bslide, b);
+  ge_dsm_precomp(Ai, A);
+
+  ge_p2_0(r);
+
+  for (i = 255; i >= 0; --i) {
+    if (aslide[i] || bslide[i]) break;
+  }
+
+  for (; i >= 0; --i) {
+    ge_p2_dbl(&t, r);
+
+    if (aslide[i] > 0) {
+      ge_p1p1_to_p3(&u, &t);
+      ge_add(&t, &u, &Ai[aslide[i]/2]);
+    } else if (aslide[i] < 0) {
+      ge_p1p1_to_p3(&u, &t);
+      ge_sub(&t, &u, &Ai[(-aslide[i])/2]);
+    }
+
+    if (bslide[i] > 0) {
+      ge_p1p1_to_p3(&u, &t);
+      ge_add(&t, &u, &Bii[bslide[i]/2]);
+    } else if (bslide[i] < 0) {
+      ge_p1p1_to_p3(&u, &t);
+      ge_sub(&t, &u, &Bii[(-bslide[i])/2]);
+    }
+
+    ge_p1p1_to_p2(r, &t);
+  }
+}
+
+//x
+void ge_mul8(ge_p1p1 *r, const ge_p2 *t) {
+  ge_p2 u;
+  ge_p2_dbl(r, t);
+  ge_p1p1_to_p2(&u, r);
+  ge_p2_dbl(r, &u);
+  ge_p1p1_to_p2(&u, r);
+  ge_p2_dbl(r, &u);
+}
+
+//x
+void ge_fromfe_frombytes_vartime(ge_p2 *r, const unsigned char *s) {
+  fe u, v, w, x, y, z;
+  unsigned char sign;
+
+  /* From fe_frombytes.c */
+
+  int64_t h0 = load_4(s);
+  int64_t h1 = load_3(s + 4) << 6;
+  int64_t h2 = load_3(s + 7) << 5;
+  int64_t h3 = load_3(s + 10) << 3;
+  int64_t h4 = load_3(s + 13) << 2;
+  int64_t h5 = load_4(s + 16);
+  int64_t h6 = load_3(s + 20) << 7;
+  int64_t h7 = load_3(s + 23) << 5;
+  int64_t h8 = load_3(s + 26) << 4;
+  int64_t h9 = load_3(s + 29) << 2;
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+
+  carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+  carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+  carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+  carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+  carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+  carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+  carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+  carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+  carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+  carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+  u[0] = h0;
+  u[1] = h1;
+  u[2] = h2;
+  u[3] = h3;
+  u[4] = h4;
+  u[5] = h5;
+  u[6] = h6;
+  u[7] = h7;
+  u[8] = h8;
+  u[9] = h9;
+
+  /* End fe_frombytes.c */
+
+  fe_sq2(v, u); /* 2 * u^2 */
+  fe_1(w);
+  fe_add(w, v, w); /* w = 2 * u^2 + 1 */
+  fe_sq(x, w); /* w^2 */
+  fe_mul(y, fe_ma2, v); /* -2 * A^2 * u^2 */
+  fe_add(x, x, y); /* x = w^2 - 2 * A^2 * u^2 */
+  fe_divpowm1(r->X, w, x); /* (w / x)^(m + 1) */
+  fe_sq(y, r->X);
+  fe_mul(x, y, x);
+  fe_sub(y, w, x);
+  fe_copy(z, fe_ma);
+  if (fe_isnonzero(y)) {
+    fe_add(y, w, x);
+    if (fe_isnonzero(y)) {
+      goto negative;
+    } else {
+      fe_mul(r->X, r->X, fe_fffb1);
+    }
+  } else {
+    fe_mul(r->X, r->X, fe_fffb2);
+  }
+  fe_mul(r->X, r->X, u); /* u * sqrt(2 * A * (A + 2) * w / x) */
+  fe_mul(z, z, v); /* -2 * A * u^2 */
+  sign = 0;
+  goto setsign;
+negative:
+  fe_mul(x, x, fe_sqrtm1);
+  fe_sub(y, w, x);
+  if (fe_isnonzero(y)) {
+    assert((fe_add(y, w, x), !fe_isnonzero(y)));
+    fe_mul(r->X, r->X, fe_fffb3);
+  } else {
+    fe_mul(r->X, r->X, fe_fffb4);
+  }
+  /* r->X = sqrt(A * (A + 2) * w / x) */
+  /* z = -A */
+  sign = 1;
+setsign:
+  if (fe_isnegative(r->X) != sign) {
+    assert(fe_isnonzero(r->X));
+    fe_neg(r->X, r->X);
+  }
+  fe_add(r->Z, z, w);
+  fe_sub(r->Y, z, w);
+  fe_mul(r->X, r->X, r->Z);
+#if !defined(NDEBUG)
+  {
+    fe check_x, check_y, check_iz, check_v;
+    fe_invert(check_iz, r->Z);
+    fe_mul(check_x, r->X, check_iz);
+    fe_mul(check_y, r->Y, check_iz);
+    fe_sq(check_x, check_x);
+    fe_sq(check_y, check_y);
+    fe_mul(check_v, check_x, check_y);
+    fe_mul(check_v, fe_d, check_v);
+    fe_add(check_v, check_v, check_x);
+    fe_sub(check_v, check_v, check_y);
+    fe_1(check_x);
+    fe_add(check_v, check_v, check_x);
+    assert(!fe_isnonzero(check_v));
+  }
+#endif
+}
+
+//x
+void sc_0(unsigned char *s) {
+  int i;
+  for (i = 0; i < 32; i++) {
+    s[i] = 0;
+  }
+}
+
+//x
+void sc_reduce32(unsigned char *s) {
+  int64_t s0 = 2097151 & load_3(s);
+  int64_t s1 = 2097151 & (load_4(s + 2) >> 5);
+  int64_t s2 = 2097151 & (load_3(s + 5) >> 2);
+  int64_t s3 = 2097151 & (load_4(s + 7) >> 7);
+  int64_t s4 = 2097151 & (load_4(s + 10) >> 4);
+  int64_t s5 = 2097151 & (load_3(s + 13) >> 1);
+  int64_t s6 = 2097151 & (load_4(s + 15) >> 6);
+  int64_t s7 = 2097151 & (load_3(s + 18) >> 3);
+  int64_t s8 = 2097151 & load_3(s + 21);
+  int64_t s9 = 2097151 & (load_4(s + 23) >> 5);
+  int64_t s10 = 2097151 & (load_3(s + 26) >> 2);
+  int64_t s11 = (load_4(s + 28) >> 7);
+  int64_t s12 = 0;
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+  int64_t carry10;
+  int64_t carry11;
+
+  carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  s[0] = s0 >> 0;
+  s[1] = s0 >> 8;
+  s[2] = (s0 >> 16) | (s1 << 5);
+  s[3] = s1 >> 3;
+  s[4] = s1 >> 11;
+  s[5] = (s1 >> 19) | (s2 << 2);
+  s[6] = s2 >> 6;
+  s[7] = (s2 >> 14) | (s3 << 7);
+  s[8] = s3 >> 1;
+  s[9] = s3 >> 9;
+  s[10] = (s3 >> 17) | (s4 << 4);
+  s[11] = s4 >> 4;
+  s[12] = s4 >> 12;
+  s[13] = (s4 >> 20) | (s5 << 1);
+  s[14] = s5 >> 7;
+  s[15] = (s5 >> 15) | (s6 << 6);
+  s[16] = s6 >> 2;
+  s[17] = s6 >> 10;
+  s[18] = (s6 >> 18) | (s7 << 3);
+  s[19] = s7 >> 5;
+  s[20] = s7 >> 13;
+  s[21] = s8 >> 0;
+  s[22] = s8 >> 8;
+  s[23] = (s8 >> 16) | (s9 << 5);
+  s[24] = s9 >> 3;
+  s[25] = s9 >> 11;
+  s[26] = (s9 >> 19) | (s10 << 2);
+  s[27] = s10 >> 6;
+  s[28] = (s10 >> 14) | (s11 << 7);
+  s[29] = s11 >> 1;
+  s[30] = s11 >> 9;
+  s[31] = s11 >> 17;
+}
+
+//x
+void sc_add(unsigned char *s, const unsigned char *a, const unsigned char *b) {
+  int64_t a0 = 2097151 & load_3(a);
+  int64_t a1 = 2097151 & (load_4(a + 2) >> 5);
+  int64_t a2 = 2097151 & (load_3(a + 5) >> 2);
+  int64_t a3 = 2097151 & (load_4(a + 7) >> 7);
+  int64_t a4 = 2097151 & (load_4(a + 10) >> 4);
+  int64_t a5 = 2097151 & (load_3(a + 13) >> 1);
+  int64_t a6 = 2097151 & (load_4(a + 15) >> 6);
+  int64_t a7 = 2097151 & (load_3(a + 18) >> 3);
+  int64_t a8 = 2097151 & load_3(a + 21);
+  int64_t a9 = 2097151 & (load_4(a + 23) >> 5);
+  int64_t a10 = 2097151 & (load_3(a + 26) >> 2);
+  int64_t a11 = (load_4(a + 28) >> 7);
+  int64_t b0 = 2097151 & load_3(b);
+  int64_t b1 = 2097151 & (load_4(b + 2) >> 5);
+  int64_t b2 = 2097151 & (load_3(b + 5) >> 2);
+  int64_t b3 = 2097151 & (load_4(b + 7) >> 7);
+  int64_t b4 = 2097151 & (load_4(b + 10) >> 4);
+  int64_t b5 = 2097151 & (load_3(b + 13) >> 1);
+  int64_t b6 = 2097151 & (load_4(b + 15) >> 6);
+  int64_t b7 = 2097151 & (load_3(b + 18) >> 3);
+  int64_t b8 = 2097151 & load_3(b + 21);
+  int64_t b9 = 2097151 & (load_4(b + 23) >> 5);
+  int64_t b10 = 2097151 & (load_3(b + 26) >> 2);
+  int64_t b11 = (load_4(b + 28) >> 7);
+  int64_t s0 = a0 + b0;
+  int64_t s1 = a1 + b1;
+  int64_t s2 = a2 + b2;
+  int64_t s3 = a3 + b3;
+  int64_t s4 = a4 + b4;
+  int64_t s5 = a5 + b5;
+  int64_t s6 = a6 + b6;
+  int64_t s7 = a7 + b7;
+  int64_t s8 = a8 + b8;
+  int64_t s9 = a9 + b9;
+  int64_t s10 = a10 + b10;
+  int64_t s11 = a11 + b11;
+  int64_t s12 = 0;
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+  int64_t carry10;
+  int64_t carry11;
+
+  carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  s[0] = s0 >> 0;
+  s[1] = s0 >> 8;
+  s[2] = (s0 >> 16) | (s1 << 5);
+  s[3] = s1 >> 3;
+  s[4] = s1 >> 11;
+  s[5] = (s1 >> 19) | (s2 << 2);
+  s[6] = s2 >> 6;
+  s[7] = (s2 >> 14) | (s3 << 7);
+  s[8] = s3 >> 1;
+  s[9] = s3 >> 9;
+  s[10] = (s3 >> 17) | (s4 << 4);
+  s[11] = s4 >> 4;
+  s[12] = s4 >> 12;
+  s[13] = (s4 >> 20) | (s5 << 1);
+  s[14] = s5 >> 7;
+  s[15] = (s5 >> 15) | (s6 << 6);
+  s[16] = s6 >> 2;
+  s[17] = s6 >> 10;
+  s[18] = (s6 >> 18) | (s7 << 3);
+  s[19] = s7 >> 5;
+  s[20] = s7 >> 13;
+  s[21] = s8 >> 0;
+  s[22] = s8 >> 8;
+  s[23] = (s8 >> 16) | (s9 << 5);
+  s[24] = s9 >> 3;
+  s[25] = s9 >> 11;
+  s[26] = (s9 >> 19) | (s10 << 2);
+  s[27] = s10 >> 6;
+  s[28] = (s10 >> 14) | (s11 << 7);
+  s[29] = s11 >> 1;
+  s[30] = s11 >> 9;
+  s[31] = s11 >> 17;
+}
+
+/* Assumes that a != INT64_MIN */
+//x c.f. lt in 32 bit ref
+static int64_t signum(int64_t a) {
+  return (a >> 63) - ((-a) >> 63);
+}
+
+//x
+int sc_check(const unsigned char *s) {
+  int64_t s0 = load_4(s);
+  int64_t s1 = load_4(s + 4);
+  int64_t s2 = load_4(s + 8);
+  int64_t s3 = load_4(s + 12);
+  int64_t s4 = load_4(s + 16);
+  int64_t s5 = load_4(s + 20);
+  int64_t s6 = load_4(s + 24);
+  int64_t s7 = load_4(s + 28);
+  return (signum(1559614444 - s0) + (signum(1477600026 - s1) << 1) + (signum(2734136534 - s2) << 2) + (signum(350157278 - s3) << 3) + (signum(-s4) << 4) + (signum(-s5) << 5) + (signum(-s6) << 6) + (signum(268435456 - s7) << 7)) >> 8;
+}
+
+//x
+int sc_isnonzero(const unsigned char *s) {
+  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;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/sha512-blocks.c b/crypt/monero_crypto/crypto_ops_builder/sha512-blocks.c
new file mode 100755
index 0000000000..c8dbf0d351
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/sha512-blocks.c
@@ -0,0 +1,239 @@
+//#include "crypto_hashblocks.h"
+
+typedef unsigned long long uint64;
+
+static uint64 load_bigendian(const unsigned char *x)
+{
+  return
+      (uint64) (x[7]) \
+  | (((uint64) (x[6])) << 8) \
+  | (((uint64) (x[5])) << 16) \
+  | (((uint64) (x[4])) << 24) \
+  | (((uint64) (x[3])) << 32) \
+  | (((uint64) (x[2])) << 40) \
+  | (((uint64) (x[1])) << 48) \
+  | (((uint64) (x[0])) << 56)
+  ;
+}
+
+static void store_bigendian(unsigned char *x,uint64 u)
+{
+  x[7] = u; u >>= 8;
+  x[6] = u; u >>= 8;
+  x[5] = u; u >>= 8;
+  x[4] = u; u >>= 8;
+  x[3] = u; u >>= 8;
+  x[2] = u; u >>= 8;
+  x[1] = u; u >>= 8;
+  x[0] = u;
+}
+
+#define SHR(x,c) ((x) >> (c))
+#define ROTR(x,c) (((x) >> (c)) | ((x) << (64 - (c))))
+
+#define Ch(x,y,z) ((x & y) ^ (~x & z))
+#define Maj(x,y,z) ((x & y) ^ (x & z) ^ (y & z))
+#define Sigma0(x) (ROTR(x,28) ^ ROTR(x,34) ^ ROTR(x,39))
+#define Sigma1(x) (ROTR(x,14) ^ ROTR(x,18) ^ ROTR(x,41))
+#define sigma0(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHR(x,7))
+#define sigma1(x) (ROTR(x,19) ^ ROTR(x,61) ^ SHR(x,6))
+
+#define M(w0,w14,w9,w1) w0 = sigma1(w14) + w9 + sigma0(w1) + w0;
+
+#define EXPAND \
+  M(w0 ,w14,w9 ,w1 ) \
+  M(w1 ,w15,w10,w2 ) \
+  M(w2 ,w0 ,w11,w3 ) \
+  M(w3 ,w1 ,w12,w4 ) \
+  M(w4 ,w2 ,w13,w5 ) \
+  M(w5 ,w3 ,w14,w6 ) \
+  M(w6 ,w4 ,w15,w7 ) \
+  M(w7 ,w5 ,w0 ,w8 ) \
+  M(w8 ,w6 ,w1 ,w9 ) \
+  M(w9 ,w7 ,w2 ,w10) \
+  M(w10,w8 ,w3 ,w11) \
+  M(w11,w9 ,w4 ,w12) \
+  M(w12,w10,w5 ,w13) \
+  M(w13,w11,w6 ,w14) \
+  M(w14,w12,w7 ,w15) \
+  M(w15,w13,w8 ,w0 )
+
+#define F(w,k) \
+  T1 = h + Sigma1(e) + Ch(e,f,g) + k + w; \
+  T2 = Sigma0(a) + Maj(a,b,c); \
+  h = g; \
+  g = f; \
+  f = e; \
+  e = d + T1; \
+  d = c; \
+  c = b; \
+  b = a; \
+  a = T1 + T2;
+
+int crypto_hashblocks(unsigned char *statebytes,const unsigned char *in,unsigned long long inlen)
+{
+  uint64 state[8];
+  uint64 a;
+  uint64 b;
+  uint64 c;
+  uint64 d;
+  uint64 e;
+  uint64 f;
+  uint64 g;
+  uint64 h;
+  uint64 T1;
+  uint64 T2;
+
+  a = load_bigendian(statebytes +  0); state[0] = a;
+  b = load_bigendian(statebytes +  8); state[1] = b;
+  c = load_bigendian(statebytes + 16); state[2] = c;
+  d = load_bigendian(statebytes + 24); state[3] = d;
+  e = load_bigendian(statebytes + 32); state[4] = e;
+  f = load_bigendian(statebytes + 40); state[5] = f;
+  g = load_bigendian(statebytes + 48); state[6] = g;
+  h = load_bigendian(statebytes + 56); state[7] = h;
+
+  while (inlen >= 128) {
+    uint64 w0  = load_bigendian(in +   0);
+    uint64 w1  = load_bigendian(in +   8);
+    uint64 w2  = load_bigendian(in +  16);
+    uint64 w3  = load_bigendian(in +  24);
+    uint64 w4  = load_bigendian(in +  32);
+    uint64 w5  = load_bigendian(in +  40);
+    uint64 w6  = load_bigendian(in +  48);
+    uint64 w7  = load_bigendian(in +  56);
+    uint64 w8  = load_bigendian(in +  64);
+    uint64 w9  = load_bigendian(in +  72);
+    uint64 w10 = load_bigendian(in +  80);
+    uint64 w11 = load_bigendian(in +  88);
+    uint64 w12 = load_bigendian(in +  96);
+    uint64 w13 = load_bigendian(in + 104);
+    uint64 w14 = load_bigendian(in + 112);
+    uint64 w15 = load_bigendian(in + 120);
+
+    F(w0 ,0x428a2f98d728ae22ULL)
+    F(w1 ,0x7137449123ef65cdULL)
+    F(w2 ,0xb5c0fbcfec4d3b2fULL)
+    F(w3 ,0xe9b5dba58189dbbcULL)
+    F(w4 ,0x3956c25bf348b538ULL)
+    F(w5 ,0x59f111f1b605d019ULL)
+    F(w6 ,0x923f82a4af194f9bULL)
+    F(w7 ,0xab1c5ed5da6d8118ULL)
+    F(w8 ,0xd807aa98a3030242ULL)
+    F(w9 ,0x12835b0145706fbeULL)
+    F(w10,0x243185be4ee4b28cULL)
+    F(w11,0x550c7dc3d5ffb4e2ULL)
+    F(w12,0x72be5d74f27b896fULL)
+    F(w13,0x80deb1fe3b1696b1ULL)
+    F(w14,0x9bdc06a725c71235ULL)
+    F(w15,0xc19bf174cf692694ULL)
+
+    EXPAND
+
+    F(w0 ,0xe49b69c19ef14ad2ULL)
+    F(w1 ,0xefbe4786384f25e3ULL)
+    F(w2 ,0x0fc19dc68b8cd5b5ULL)
+    F(w3 ,0x240ca1cc77ac9c65ULL)
+    F(w4 ,0x2de92c6f592b0275ULL)
+    F(w5 ,0x4a7484aa6ea6e483ULL)
+    F(w6 ,0x5cb0a9dcbd41fbd4ULL)
+    F(w7 ,0x76f988da831153b5ULL)
+    F(w8 ,0x983e5152ee66dfabULL)
+    F(w9 ,0xa831c66d2db43210ULL)
+    F(w10,0xb00327c898fb213fULL)
+    F(w11,0xbf597fc7beef0ee4ULL)
+    F(w12,0xc6e00bf33da88fc2ULL)
+    F(w13,0xd5a79147930aa725ULL)
+    F(w14,0x06ca6351e003826fULL)
+    F(w15,0x142929670a0e6e70ULL)
+
+    EXPAND
+
+    F(w0 ,0x27b70a8546d22ffcULL)
+    F(w1 ,0x2e1b21385c26c926ULL)
+    F(w2 ,0x4d2c6dfc5ac42aedULL)
+    F(w3 ,0x53380d139d95b3dfULL)
+    F(w4 ,0x650a73548baf63deULL)
+    F(w5 ,0x766a0abb3c77b2a8ULL)
+    F(w6 ,0x81c2c92e47edaee6ULL)
+    F(w7 ,0x92722c851482353bULL)
+    F(w8 ,0xa2bfe8a14cf10364ULL)
+    F(w9 ,0xa81a664bbc423001ULL)
+    F(w10,0xc24b8b70d0f89791ULL)
+    F(w11,0xc76c51a30654be30ULL)
+    F(w12,0xd192e819d6ef5218ULL)
+    F(w13,0xd69906245565a910ULL)
+    F(w14,0xf40e35855771202aULL)
+    F(w15,0x106aa07032bbd1b8ULL)
+
+    EXPAND
+
+    F(w0 ,0x19a4c116b8d2d0c8ULL)
+    F(w1 ,0x1e376c085141ab53ULL)
+    F(w2 ,0x2748774cdf8eeb99ULL)
+    F(w3 ,0x34b0bcb5e19b48a8ULL)
+    F(w4 ,0x391c0cb3c5c95a63ULL)
+    F(w5 ,0x4ed8aa4ae3418acbULL)
+    F(w6 ,0x5b9cca4f7763e373ULL)
+    F(w7 ,0x682e6ff3d6b2b8a3ULL)
+    F(w8 ,0x748f82ee5defb2fcULL)
+    F(w9 ,0x78a5636f43172f60ULL)
+    F(w10,0x84c87814a1f0ab72ULL)
+    F(w11,0x8cc702081a6439ecULL)
+    F(w12,0x90befffa23631e28ULL)
+    F(w13,0xa4506cebde82bde9ULL)
+    F(w14,0xbef9a3f7b2c67915ULL)
+    F(w15,0xc67178f2e372532bULL)
+
+    EXPAND
+
+    F(w0 ,0xca273eceea26619cULL)
+    F(w1 ,0xd186b8c721c0c207ULL)
+    F(w2 ,0xeada7dd6cde0eb1eULL)
+    F(w3 ,0xf57d4f7fee6ed178ULL)
+    F(w4 ,0x06f067aa72176fbaULL)
+    F(w5 ,0x0a637dc5a2c898a6ULL)
+    F(w6 ,0x113f9804bef90daeULL)
+    F(w7 ,0x1b710b35131c471bULL)
+    F(w8 ,0x28db77f523047d84ULL)
+    F(w9 ,0x32caab7b40c72493ULL)
+    F(w10,0x3c9ebe0a15c9bebcULL)
+    F(w11,0x431d67c49c100d4cULL)
+    F(w12,0x4cc5d4becb3e42b6ULL)
+    F(w13,0x597f299cfc657e2aULL)
+    F(w14,0x5fcb6fab3ad6faecULL)
+    F(w15,0x6c44198c4a475817ULL)
+
+    a += state[0];
+    b += state[1];
+    c += state[2];
+    d += state[3];
+    e += state[4];
+    f += state[5];
+    g += state[6];
+    h += state[7];
+  
+    state[0] = a;
+    state[1] = b;
+    state[2] = c;
+    state[3] = d;
+    state[4] = e;
+    state[5] = f;
+    state[6] = g;
+    state[7] = h;
+
+    in += 128;
+    inlen -= 128;
+  }
+
+  store_bigendian(statebytes +  0,state[0]);
+  store_bigendian(statebytes +  8,state[1]);
+  store_bigendian(statebytes + 16,state[2]);
+  store_bigendian(statebytes + 24,state[3]);
+  store_bigendian(statebytes + 32,state[4]);
+  store_bigendian(statebytes + 40,state[5]);
+  store_bigendian(statebytes + 48,state[6]);
+  store_bigendian(statebytes + 56,state[7]);
+
+  return inlen;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/sha512-hash.c b/crypt/monero_crypto/crypto_ops_builder/sha512-hash.c
new file mode 100755
index 0000000000..f2f292505c
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/sha512-hash.c
@@ -0,0 +1,72 @@
+/*
+20080913
+D. J. Bernstein
+Public domain.
+*/
+
+#include "sha512.h"
+
+extern int crypto_hashblocks(unsigned char *statebytes,const unsigned char *in,unsigned long long inlen);
+
+#define blocks crypto_hashblocks
+
+static const unsigned char iv[64] = {
+  0x6a,0x09,0xe6,0x67,0xf3,0xbc,0xc9,0x08,
+  0xbb,0x67,0xae,0x85,0x84,0xca,0xa7,0x3b,
+  0x3c,0x6e,0xf3,0x72,0xfe,0x94,0xf8,0x2b,
+  0xa5,0x4f,0xf5,0x3a,0x5f,0x1d,0x36,0xf1,
+  0x51,0x0e,0x52,0x7f,0xad,0xe6,0x82,0xd1,
+  0x9b,0x05,0x68,0x8c,0x2b,0x3e,0x6c,0x1f,
+  0x1f,0x83,0xd9,0xab,0xfb,0x41,0xbd,0x6b,
+  0x5b,0xe0,0xcd,0x19,0x13,0x7e,0x21,0x79
+} ;
+
+typedef unsigned long long uint64;
+
+int crypto_hash_sha512(unsigned char *out,const unsigned char *in,unsigned long long inlen)
+{
+  unsigned char h[64];
+  unsigned char padded[256];
+  int i;
+  unsigned long long bytes = inlen;
+
+  for (i = 0;i < 64;++i) h[i] = iv[i];
+
+  blocks(h,in,inlen);
+  in += inlen;
+  inlen &= 127;
+  in -= inlen;
+
+  for (i = 0;i < inlen;++i) padded[i] = in[i];
+  padded[inlen] = 0x80;
+
+  if (inlen < 112) {
+    for (i = inlen + 1;i < 119;++i) padded[i] = 0;
+    padded[119] = bytes >> 61;
+    padded[120] = bytes >> 53;
+    padded[121] = bytes >> 45;
+    padded[122] = bytes >> 37;
+    padded[123] = bytes >> 29;
+    padded[124] = bytes >> 21;
+    padded[125] = bytes >> 13;
+    padded[126] = bytes >> 5;
+    padded[127] = bytes << 3;
+    blocks(h,padded,128);
+  } else {
+    for (i = inlen + 1;i < 247;++i) padded[i] = 0;
+    padded[247] = bytes >> 61;
+    padded[248] = bytes >> 53;
+    padded[249] = bytes >> 45;
+    padded[250] = bytes >> 37;
+    padded[251] = bytes >> 29;
+    padded[252] = bytes >> 21;
+    padded[253] = bytes >> 13;
+    padded[254] = bytes >> 5;
+    padded[255] = bytes << 3;
+    blocks(h,padded,256);
+  }
+
+  for (i = 0;i < 64;++i) out[i] = h[i];
+
+  return 0;
+}
diff --git a/crypt/monero_crypto/crypto_ops_builder/sha512.h b/crypt/monero_crypto/crypto_ops_builder/sha512.h
new file mode 100755
index 0000000000..37376b15de
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/sha512.h
@@ -0,0 +1,4 @@
+extern int crypto_hashblocks(unsigned char *statebytes,const unsigned char *in,unsigned long long inlen);
+extern int crypto_hash_sha512(unsigned char *out,const unsigned char *in,unsigned long long inlen);
+
+#define crypto_hash_sha512_BYTES 64
diff --git a/crypt/monero_crypto/crypto_ops_builder/verify.c b/crypt/monero_crypto/crypto_ops_builder/verify.c
new file mode 100755
index 0000000000..a04186b607
--- /dev/null
+++ b/crypt/monero_crypto/crypto_ops_builder/verify.c
@@ -0,0 +1,40 @@
+#include "crypto_verify_32.h"
+
+int crypto_verify_32(const unsigned char *x,const unsigned char *y)
+{
+  unsigned int differentbits = 0;
+#define F(i) differentbits |= x[i] ^ y[i];
+  F(0)
+  F(1)
+  F(2)
+  F(3)
+  F(4)
+  F(5)
+  F(6)
+  F(7)
+  F(8)
+  F(9)
+  F(10)
+  F(11)
+  F(12)
+  F(13)
+  F(14)
+  F(15)
+  F(16)
+  F(17)
+  F(18)
+  F(19)
+  F(20)
+  F(21)
+  F(22)
+  F(23)
+  F(24)
+  F(25)
+  F(26)
+  F(27)
+  F(28)
+  F(29)
+  F(30)
+  F(31)
+  return (1 & ((differentbits - 1) >> 8)) - 1;
+}
diff --git a/crypt/monero_crypto/generic-ops.h b/crypt/monero_crypto/generic-ops.h
new file mode 100644
index 0000000000..1a135ffcf5
--- /dev/null
+++ b/crypt/monero_crypto/generic-ops.h
@@ -0,0 +1,62 @@
+// 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
+
+#pragma once
+
+#include <cstddef>
+#include <cstring>
+#include <functional>
+
+#define CRYPTO_MAKE_COMPARABLE(type) \
+namespace crypto { \
+  inline bool operator==(const type &_v1, const type &_v2) { \
+    return std::memcmp(&_v1, &_v2, sizeof(type)) == 0; \
+  } \
+  inline bool operator!=(const type &_v1, const type &_v2) { \
+    return std::memcmp(&_v1, &_v2, sizeof(type)) != 0; \
+  } \
+}
+
+#define CRYPTO_MAKE_HASHABLE(type) \
+CRYPTO_MAKE_COMPARABLE(type) \
+namespace crypto { \
+  static_assert(sizeof(std::size_t) <= sizeof(type), "Size of " #type " must be at least that of size_t"); \
+  inline std::size_t hash_value(const type &_v) { \
+    return reinterpret_cast<const std::size_t &>(_v); \
+  } \
+} \
+namespace std { \
+  template<> \
+  struct hash<crypto::type> { \
+    std::size_t operator()(const crypto::type &_v) const { \
+      return reinterpret_cast<const std::size_t &>(_v); \
+    } \
+  }; \
+}
diff --git a/crypt/monero_crypto/groestl.c b/crypt/monero_crypto/groestl.c
new file mode 100644
index 0000000000..c8258add33
--- /dev/null
+++ b/crypt/monero_crypto/groestl.c
@@ -0,0 +1,360 @@
+/* hash.c     April 2012
+ * Groestl ANSI C code optimised for 32-bit machines
+ * Author: Thomas Krinninger
+ *
+ *  This work is based on the implementation of
+ *          Soeren S. Thomsen and Krystian Matusiewicz
+ *          
+ *
+ */
+
+#include <stddef.h>
+#include "groestl.h"
+#include "groestl_tables.h"
+
+#define P_TYPE 0
+#define Q_TYPE 1
+
+const uint8_t shift_Values[2][8] = {{0,1,2,3,4,5,6,7},{1,3,5,7,0,2,4,6}};
+
+const uint8_t indices_cyclic[15] = {0,1,2,3,4,5,6,7,0,1,2,3,4,5,6};
+
+
+#define ROTATE_COLUMN_DOWN(v1, v2, amount_bytes, temp_var) {temp_var = (v1<<(8*amount_bytes))|(v2>>(8*(4-amount_bytes))); \
+															v2 = (v2<<(8*amount_bytes))|(v1>>(8*(4-amount_bytes))); \
+															v1 = temp_var;}
+  
+
+#define COLUMN(x,y,i,c0,c1,c2,c3,c4,c5,c6,c7,tv1,tv2,tu,tl,t)				\
+   tu = T[2*(uint32_t)x[4*c0+0]];			    \
+   tl = T[2*(uint32_t)x[4*c0+0]+1];		    \
+   tv1 = T[2*(uint32_t)x[4*c1+1]];			\
+   tv2 = T[2*(uint32_t)x[4*c1+1]+1];			\
+   ROTATE_COLUMN_DOWN(tv1,tv2,1,t)	\
+   tu ^= tv1;						\
+   tl ^= tv2;						\
+   tv1 = T[2*(uint32_t)x[4*c2+2]];			\
+   tv2 = T[2*(uint32_t)x[4*c2+2]+1];			\
+   ROTATE_COLUMN_DOWN(tv1,tv2,2,t)	\
+   tu ^= tv1;						\
+   tl ^= tv2;   					\
+   tv1 = T[2*(uint32_t)x[4*c3+3]];			\
+   tv2 = T[2*(uint32_t)x[4*c3+3]+1];			\
+   ROTATE_COLUMN_DOWN(tv1,tv2,3,t)	\
+   tu ^= tv1;						\
+   tl ^= tv2;						\
+   tl ^= T[2*(uint32_t)x[4*c4+0]];			\
+   tu ^= T[2*(uint32_t)x[4*c4+0]+1];			\
+   tv1 = T[2*(uint32_t)x[4*c5+1]];			\
+   tv2 = T[2*(uint32_t)x[4*c5+1]+1];			\
+   ROTATE_COLUMN_DOWN(tv1,tv2,1,t)	\
+   tl ^= tv1;						\
+   tu ^= tv2;						\
+   tv1 = T[2*(uint32_t)x[4*c6+2]];			\
+   tv2 = T[2*(uint32_t)x[4*c6+2]+1];			\
+   ROTATE_COLUMN_DOWN(tv1,tv2,2,t)	\
+   tl ^= tv1;						\
+   tu ^= tv2;   					\
+   tv1 = T[2*(uint32_t)x[4*c7+3]];			\
+   tv2 = T[2*(uint32_t)x[4*c7+3]+1];			\
+   ROTATE_COLUMN_DOWN(tv1,tv2,3,t)	\
+   tl ^= tv1;						\
+   tu ^= tv2;						\
+   y[i] = tu;						\
+   y[i+1] = tl;
+
+
+/* compute one round of P (short variants) */
+static void RND512P(uint8_t *x, uint32_t *y, uint32_t r) {
+  uint32_t temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp;
+  uint32_t* x32 = (uint32_t*)x;
+  x32[ 0] ^= 0x00000000^r;
+  x32[ 2] ^= 0x00000010^r;
+  x32[ 4] ^= 0x00000020^r;
+  x32[ 6] ^= 0x00000030^r;
+  x32[ 8] ^= 0x00000040^r;
+  x32[10] ^= 0x00000050^r;
+  x32[12] ^= 0x00000060^r;
+  x32[14] ^= 0x00000070^r;
+  COLUMN(x,y, 0,  0,  2,  4,  6,  9, 11, 13, 15, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
+  COLUMN(x,y, 2,  2,  4,  6,  8, 11, 13, 15,  1, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
+  COLUMN(x,y, 4,  4,  6,  8, 10, 13, 15,  1,  3, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
+  COLUMN(x,y, 6,  6,  8, 10, 12, 15,  1,  3,  5, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
+  COLUMN(x,y, 8,  8, 10, 12, 14,  1,  3,  5,  7, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
+  COLUMN(x,y,10, 10, 12, 14,  0,  3,  5,  7,  9, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
+  COLUMN(x,y,12, 12, 14,  0,  2,  5,  7,  9, 11, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
+  COLUMN(x,y,14, 14,  0,  2,  4,  7,  9, 11, 13, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
+}
+
+/* compute one round of Q (short variants) */
+static void RND512Q(uint8_t *x, uint32_t *y, uint32_t r) {
+  uint32_t temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp;
+  uint32_t* x32 = (uint32_t*)x;
+  x32[ 0] = ~x32[ 0];
+  x32[ 1] ^= 0xffffffff^r;
+  x32[ 2] = ~x32[ 2];
+  x32[ 3] ^= 0xefffffff^r;
+  x32[ 4] = ~x32[ 4];
+  x32[ 5] ^= 0xdfffffff^r;
+  x32[ 6] = ~x32[ 6];
+  x32[ 7] ^= 0xcfffffff^r;
+  x32[ 8] = ~x32[ 8];
+  x32[ 9] ^= 0xbfffffff^r;
+  x32[10] = ~x32[10];
+  x32[11] ^= 0xafffffff^r;
+  x32[12] = ~x32[12];
+  x32[13] ^= 0x9fffffff^r;
+  x32[14] = ~x32[14];
+  x32[15] ^= 0x8fffffff^r;
+  COLUMN(x,y, 0,  2,  6, 10, 14,  1,  5,  9, 13, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
+  COLUMN(x,y, 2,  4,  8, 12,  0,  3,  7, 11, 15, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
+  COLUMN(x,y, 4,  6, 10, 14,  2,  5,  9, 13,  1, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
+  COLUMN(x,y, 6,  8, 12,  0,  4,  7, 11, 15,  3, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
+  COLUMN(x,y, 8, 10, 14,  2,  6,  9, 13,  1,  5, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
+  COLUMN(x,y,10, 12,  0,  4,  8, 11, 15,  3,  7, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
+  COLUMN(x,y,12, 14,  2,  6, 10, 13,  1,  5,  9, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
+  COLUMN(x,y,14,  0,  4,  8, 12, 15,  3,  7, 11, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
+}
+
+/* compute compression function (short variants) */
+static void F512(uint32_t *h, const uint32_t *m) {
+  int i;
+  uint32_t Ptmp[2*COLS512];
+  uint32_t Qtmp[2*COLS512];
+  uint32_t y[2*COLS512];
+  uint32_t z[2*COLS512];
+
+  for (i = 0; i < 2*COLS512; i++) {
+    z[i] = m[i];
+    Ptmp[i] = h[i]^m[i];
+  }
+
+  /* compute Q(m) */
+  RND512Q((uint8_t*)z, y, 0x00000000);
+  RND512Q((uint8_t*)y, z, 0x01000000);
+  RND512Q((uint8_t*)z, y, 0x02000000);
+  RND512Q((uint8_t*)y, z, 0x03000000);
+  RND512Q((uint8_t*)z, y, 0x04000000);
+  RND512Q((uint8_t*)y, z, 0x05000000);
+  RND512Q((uint8_t*)z, y, 0x06000000);
+  RND512Q((uint8_t*)y, z, 0x07000000);
+  RND512Q((uint8_t*)z, y, 0x08000000);
+  RND512Q((uint8_t*)y, Qtmp, 0x09000000);
+
+  /* compute P(h+m) */
+  RND512P((uint8_t*)Ptmp, y, 0x00000000);
+  RND512P((uint8_t*)y, z, 0x00000001);
+  RND512P((uint8_t*)z, y, 0x00000002);
+  RND512P((uint8_t*)y, z, 0x00000003);
+  RND512P((uint8_t*)z, y, 0x00000004);
+  RND512P((uint8_t*)y, z, 0x00000005);
+  RND512P((uint8_t*)z, y, 0x00000006);
+  RND512P((uint8_t*)y, z, 0x00000007);
+  RND512P((uint8_t*)z, y, 0x00000008);
+  RND512P((uint8_t*)y, Ptmp, 0x00000009);
+
+  /* compute P(h+m) + Q(m) + h */
+  for (i = 0; i < 2*COLS512; i++) {
+    h[i] ^= Ptmp[i]^Qtmp[i];
+  }
+}
+
+
+/* digest up to msglen bytes of input (full blocks only) */
+static void Transform(hashState *ctx, 
+	       const uint8_t *input, 
+	       int msglen) {
+
+  /* digest message, one block at a time */
+  for (; msglen >= SIZE512; 
+       msglen -= SIZE512, input += SIZE512) {
+    F512(ctx->chaining,(uint32_t*)input);
+
+    /* increment block counter */
+    ctx->block_counter1++;
+    if (ctx->block_counter1 == 0) ctx->block_counter2++;
+  }
+}
+
+/* given state h, do h <- P(h)+h */
+static void OutputTransformation(hashState *ctx) {
+  int j;
+  uint32_t temp[2*COLS512];
+  uint32_t y[2*COLS512];
+  uint32_t z[2*COLS512];
+
+
+
+	for (j = 0; j < 2*COLS512; j++) {
+	  temp[j] = ctx->chaining[j];
+	}
+	RND512P((uint8_t*)temp, y, 0x00000000);
+	RND512P((uint8_t*)y, z, 0x00000001);
+	RND512P((uint8_t*)z, y, 0x00000002);
+	RND512P((uint8_t*)y, z, 0x00000003);
+	RND512P((uint8_t*)z, y, 0x00000004);
+	RND512P((uint8_t*)y, z, 0x00000005);
+	RND512P((uint8_t*)z, y, 0x00000006);
+	RND512P((uint8_t*)y, z, 0x00000007);
+	RND512P((uint8_t*)z, y, 0x00000008);
+	RND512P((uint8_t*)y, temp, 0x00000009);
+	for (j = 0; j < 2*COLS512; j++) {
+	  ctx->chaining[j] ^= temp[j];
+	}									  
+}
+
+/* initialise context */
+static void Init(hashState* ctx) {
+  /* allocate memory for state and data buffer */
+
+  for(size_t i = 0; i < (SIZE512/sizeof(uint32_t)); i++)
+  {
+	ctx->chaining[i] = 0;
+  }
+
+  /* set initial value */
+  ctx->chaining[2*COLS512-1] = u32BIG((uint32_t)HASH_BIT_LEN);
+
+  /* set other variables */
+  ctx->buf_ptr = 0;
+  ctx->block_counter1 = 0;
+  ctx->block_counter2 = 0;
+  ctx->bits_in_last_byte = 0;
+}
+
+/* update state with databitlen bits of input */
+static void Update(hashState* ctx,
+		  const BitSequence* input,
+		  DataLength databitlen) {
+  int index = 0;
+  int msglen = (int)(databitlen/8);
+  int rem = (int)(databitlen%8);
+
+  /* if the buffer contains data that has not yet been digested, first
+     add data to buffer until full */
+  if (ctx->buf_ptr) {
+    while (ctx->buf_ptr < SIZE512 && index < msglen) {
+      ctx->buffer[(int)ctx->buf_ptr++] = input[index++];
+    }
+    if (ctx->buf_ptr < SIZE512) {
+      /* buffer still not full, return */
+      if (rem) {
+	ctx->bits_in_last_byte = rem;
+	ctx->buffer[(int)ctx->buf_ptr++] = input[index];
+      }
+      return;
+    }
+
+    /* digest buffer */
+    ctx->buf_ptr = 0;
+    Transform(ctx, ctx->buffer, SIZE512);
+  }
+
+  /* digest bulk of message */
+  Transform(ctx, input+index, msglen-index);
+  index += ((msglen-index)/SIZE512)*SIZE512;
+
+  /* store remaining data in buffer */
+  while (index < msglen) {
+    ctx->buffer[(int)ctx->buf_ptr++] = input[index++];
+  }
+
+  /* if non-integral number of bytes have been supplied, store
+     remaining bits in last byte, together with information about
+     number of bits */
+  if (rem) {
+    ctx->bits_in_last_byte = rem;
+    ctx->buffer[(int)ctx->buf_ptr++] = input[index];
+  }
+}
+
+#define BILB ctx->bits_in_last_byte
+
+/* finalise: process remaining data (including padding), perform
+   output transformation, and write hash result to 'output' */
+static void Final(hashState* ctx,
+		 BitSequence* output) {
+  int i, j = 0, hashbytelen = HASH_BIT_LEN/8;
+  uint8_t *s = (BitSequence*)ctx->chaining;
+
+  /* pad with '1'-bit and first few '0'-bits */
+  if (BILB) {
+    ctx->buffer[(int)ctx->buf_ptr-1] &= ((1<<BILB)-1)<<(8-BILB);
+    ctx->buffer[(int)ctx->buf_ptr-1] ^= 0x1<<(7-BILB);
+    BILB = 0;
+  }
+  else ctx->buffer[(int)ctx->buf_ptr++] = 0x80;
+
+  /* pad with '0'-bits */
+  if (ctx->buf_ptr > SIZE512-LENGTHFIELDLEN) {
+    /* padding requires two blocks */
+    while (ctx->buf_ptr < SIZE512) {
+      ctx->buffer[(int)ctx->buf_ptr++] = 0;
+    }
+    /* digest first padding block */
+    Transform(ctx, ctx->buffer, SIZE512);
+    ctx->buf_ptr = 0;
+  }
+  while (ctx->buf_ptr < SIZE512-LENGTHFIELDLEN) {
+    ctx->buffer[(int)ctx->buf_ptr++] = 0;
+  }
+
+  /* length padding */
+  ctx->block_counter1++;
+  if (ctx->block_counter1 == 0) ctx->block_counter2++;
+  ctx->buf_ptr = SIZE512;
+
+  while (ctx->buf_ptr > SIZE512-(int)sizeof(uint32_t)) {
+    ctx->buffer[(int)--ctx->buf_ptr] = (uint8_t)ctx->block_counter1;
+    ctx->block_counter1 >>= 8;
+  }
+  while (ctx->buf_ptr > SIZE512-LENGTHFIELDLEN) {
+    ctx->buffer[(int)--ctx->buf_ptr] = (uint8_t)ctx->block_counter2;
+    ctx->block_counter2 >>= 8;
+  }
+  /* digest final padding block */
+  Transform(ctx, ctx->buffer, SIZE512); 
+  /* perform output transformation */
+  OutputTransformation(ctx);
+
+  /* store hash result in output */
+  for (i = SIZE512-hashbytelen; i < SIZE512; i++,j++) {
+    output[j] = s[i];
+  }
+
+  /* zeroise relevant variables and deallocate memory */
+  for (i = 0; i < COLS512; i++) {
+    ctx->chaining[i] = 0;
+  }
+  for (i = 0; i < SIZE512; i++) {
+    ctx->buffer[i] = 0;
+  }
+}
+
+/* hash bit sequence */
+void groestl(const BitSequence* data, 
+		DataLength databitlen,
+		BitSequence* hashval) {
+
+  hashState context;
+
+  /* initialise */
+    Init(&context);
+
+
+  /* process message */
+  Update(&context, data, databitlen);
+
+  /* finalise */
+  Final(&context, hashval);
+}
+/*
+static int crypto_hash(unsigned char *out,
+		const unsigned char *in,
+		unsigned long long len)
+{
+  groestl(in, 8*len, out);
+  return 0;
+}
+
+*/
diff --git a/crypt/monero_crypto/groestl.h b/crypt/monero_crypto/groestl.h
new file mode 100644
index 0000000000..89a073a4c3
--- /dev/null
+++ b/crypt/monero_crypto/groestl.h
@@ -0,0 +1,88 @@
+// 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.
+
+#ifndef __hash_h
+#define __hash_h
+/*
+#include "crypto_uint8.h"
+#include "crypto_uint32.h"
+#include "crypto_uint64.h"
+#include "crypto_hash.h" 
+
+typedef crypto_uint8 uint8_t; 
+typedef crypto_uint32 uint32_t; 
+typedef crypto_uint64 uint64_t;
+*/
+#include <stdint.h>
+
+/* some sizes (number of bytes) */
+#define ROWS 8
+#define LENGTHFIELDLEN ROWS
+#define COLS512 8
+
+#define SIZE512 (ROWS*COLS512)
+
+#define ROUNDS512 10
+#define HASH_BIT_LEN 256
+
+#define ROTL32(v, n) ((((v)<<(n))|((v)>>(32-(n))))&li_32(ffffffff))
+
+
+#define li_32(h) 0x##h##u
+#define EXT_BYTE(var,n) ((uint8_t)((uint32_t)(var) >> (8*n)))
+#define u32BIG(a)				\
+  ((ROTL32(a,8) & li_32(00FF00FF)) |		\
+   (ROTL32(a,24) & li_32(FF00FF00)))
+
+
+/* NIST API begin */
+typedef unsigned char BitSequence;
+typedef unsigned long long DataLength;
+typedef struct {
+  uint32_t chaining[SIZE512/sizeof(uint32_t)];            /* actual state */
+  uint32_t block_counter1,
+  block_counter2;         /* message block counter(s) */
+  BitSequence buffer[SIZE512];      /* data buffer */
+  int buf_ptr;              /* data buffer pointer */
+  int bits_in_last_byte;    /* no. of message bits in last byte of
+			       data buffer */
+} hashState;
+
+/*void Init(hashState*);
+void Update(hashState*, const BitSequence*, DataLength);
+void Final(hashState*, BitSequence*); */
+void groestl(const BitSequence*, DataLength, BitSequence*);
+/* NIST API end   */
+
+/*
+int crypto_hash(unsigned char *out,
+		const unsigned char *in,
+		unsigned long long len);
+*/
+
+#endif /* __hash_h */
diff --git a/crypt/monero_crypto/groestl_tables.h b/crypt/monero_crypto/groestl_tables.h
new file mode 100644
index 0000000000..8fa6d7a832
--- /dev/null
+++ b/crypt/monero_crypto/groestl_tables.h
@@ -0,0 +1,66 @@
+// 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.
+
+#ifndef __tables_h
+#define __tables_h
+
+
+const uint32_t T[512] = {0xa5f432c6, 0xc6a597f4, 0x84976ff8, 0xf884eb97, 0x99b05eee, 0xee99c7b0, 0x8d8c7af6, 0xf68df78c, 0xd17e8ff, 0xff0de517, 0xbddc0ad6, 0xd6bdb7dc, 0xb1c816de, 0xdeb1a7c8, 0x54fc6d91, 0x915439fc
+, 0x50f09060, 0x6050c0f0, 0x3050702, 0x2030405, 0xa9e02ece, 0xcea987e0, 0x7d87d156, 0x567dac87, 0x192bcce7, 0xe719d52b, 0x62a613b5, 0xb56271a6, 0xe6317c4d, 0x4de69a31, 0x9ab559ec, 0xec9ac3b5
+, 0x45cf408f, 0x8f4505cf, 0x9dbca31f, 0x1f9d3ebc, 0x40c04989, 0x894009c0, 0x879268fa, 0xfa87ef92, 0x153fd0ef, 0xef15c53f, 0xeb2694b2, 0xb2eb7f26, 0xc940ce8e, 0x8ec90740, 0xb1de6fb, 0xfb0bed1d
+, 0xec2f6e41, 0x41ec822f, 0x67a91ab3, 0xb3677da9, 0xfd1c435f, 0x5ffdbe1c, 0xea256045, 0x45ea8a25, 0xbfdaf923, 0x23bf46da, 0xf7025153, 0x53f7a602, 0x96a145e4, 0xe496d3a1, 0x5bed769b, 0x9b5b2ded
+, 0xc25d2875, 0x75c2ea5d, 0x1c24c5e1, 0xe11cd924, 0xaee9d43d, 0x3dae7ae9, 0x6abef24c, 0x4c6a98be, 0x5aee826c, 0x6c5ad8ee, 0x41c3bd7e, 0x7e41fcc3, 0x206f3f5, 0xf502f106, 0x4fd15283, 0x834f1dd1
+, 0x5ce48c68, 0x685cd0e4, 0xf4075651, 0x51f4a207, 0x345c8dd1, 0xd134b95c, 0x818e1f9, 0xf908e918, 0x93ae4ce2, 0xe293dfae, 0x73953eab, 0xab734d95, 0x53f59762, 0x6253c4f5, 0x3f416b2a, 0x2a3f5441
+, 0xc141c08, 0x80c1014, 0x52f66395, 0x955231f6, 0x65afe946, 0x46658caf, 0x5ee27f9d, 0x9d5e21e2, 0x28784830, 0x30286078, 0xa1f8cf37, 0x37a16ef8, 0xf111b0a, 0xa0f1411, 0xb5c4eb2f, 0x2fb55ec4
+, 0x91b150e, 0xe091c1b, 0x365a7e24, 0x2436485a, 0x9bb6ad1b, 0x1b9b36b6, 0x3d4798df, 0xdf3da547, 0x266aa7cd, 0xcd26816a, 0x69bbf54e, 0x4e699cbb, 0xcd4c337f, 0x7fcdfe4c, 0x9fba50ea, 0xea9fcfba
+, 0x1b2d3f12, 0x121b242d, 0x9eb9a41d, 0x1d9e3ab9, 0x749cc458, 0x5874b09c, 0x2e724634, 0x342e6872, 0x2d774136, 0x362d6c77, 0xb2cd11dc, 0xdcb2a3cd, 0xee299db4, 0xb4ee7329, 0xfb164d5b, 0x5bfbb616
+, 0xf601a5a4, 0xa4f65301, 0x4dd7a176, 0x764decd7, 0x61a314b7, 0xb76175a3, 0xce49347d, 0x7dcefa49, 0x7b8ddf52, 0x527ba48d, 0x3e429fdd, 0xdd3ea142, 0x7193cd5e, 0x5e71bc93, 0x97a2b113, 0x139726a2
+, 0xf504a2a6, 0xa6f55704, 0x68b801b9, 0xb96869b8, 0x0, 0x0, 0x2c74b5c1, 0xc12c9974, 0x60a0e040, 0x406080a0, 0x1f21c2e3, 0xe31fdd21, 0xc8433a79, 0x79c8f243, 0xed2c9ab6, 0xb6ed772c
+, 0xbed90dd4, 0xd4beb3d9, 0x46ca478d, 0x8d4601ca, 0xd9701767, 0x67d9ce70, 0x4bddaf72, 0x724be4dd, 0xde79ed94, 0x94de3379, 0xd467ff98, 0x98d42b67, 0xe82393b0, 0xb0e87b23, 0x4ade5b85, 0x854a11de
+, 0x6bbd06bb, 0xbb6b6dbd, 0x2a7ebbc5, 0xc52a917e, 0xe5347b4f, 0x4fe59e34, 0x163ad7ed, 0xed16c13a, 0xc554d286, 0x86c51754, 0xd762f89a, 0x9ad72f62, 0x55ff9966, 0x6655ccff, 0x94a7b611, 0x119422a7
+, 0xcf4ac08a, 0x8acf0f4a, 0x1030d9e9, 0xe910c930, 0x60a0e04, 0x406080a, 0x819866fe, 0xfe81e798, 0xf00baba0, 0xa0f05b0b, 0x44ccb478, 0x7844f0cc, 0xbad5f025, 0x25ba4ad5, 0xe33e754b, 0x4be3963e
+, 0xf30eaca2, 0xa2f35f0e, 0xfe19445d, 0x5dfeba19, 0xc05bdb80, 0x80c01b5b, 0x8a858005, 0x58a0a85, 0xadecd33f, 0x3fad7eec, 0xbcdffe21, 0x21bc42df, 0x48d8a870, 0x7048e0d8, 0x40cfdf1, 0xf104f90c
+, 0xdf7a1963, 0x63dfc67a, 0xc1582f77, 0x77c1ee58, 0x759f30af, 0xaf75459f, 0x63a5e742, 0x426384a5, 0x30507020, 0x20304050, 0x1a2ecbe5, 0xe51ad12e, 0xe12effd, 0xfd0ee112, 0x6db708bf, 0xbf6d65b7
+, 0x4cd45581, 0x814c19d4, 0x143c2418, 0x1814303c, 0x355f7926, 0x26354c5f, 0x2f71b2c3, 0xc32f9d71, 0xe13886be, 0xbee16738, 0xa2fdc835, 0x35a26afd, 0xcc4fc788, 0x88cc0b4f, 0x394b652e, 0x2e395c4b
+, 0x57f96a93, 0x93573df9, 0xf20d5855, 0x55f2aa0d, 0x829d61fc, 0xfc82e39d, 0x47c9b37a, 0x7a47f4c9, 0xacef27c8, 0xc8ac8bef, 0xe73288ba, 0xbae76f32, 0x2b7d4f32, 0x322b647d, 0x95a442e6, 0xe695d7a4
+, 0xa0fb3bc0, 0xc0a09bfb, 0x98b3aa19, 0x199832b3, 0xd168f69e, 0x9ed12768, 0x7f8122a3, 0xa37f5d81, 0x66aaee44, 0x446688aa, 0x7e82d654, 0x547ea882, 0xabe6dd3b, 0x3bab76e6, 0x839e950b, 0xb83169e
+, 0xca45c98c, 0x8cca0345, 0x297bbcc7, 0xc729957b, 0xd36e056b, 0x6bd3d66e, 0x3c446c28, 0x283c5044, 0x798b2ca7, 0xa779558b, 0xe23d81bc, 0xbce2633d, 0x1d273116, 0x161d2c27, 0x769a37ad, 0xad76419a
+, 0x3b4d96db, 0xdb3bad4d, 0x56fa9e64, 0x6456c8fa, 0x4ed2a674, 0x744ee8d2, 0x1e223614, 0x141e2822, 0xdb76e492, 0x92db3f76, 0xa1e120c, 0xc0a181e, 0x6cb4fc48, 0x486c90b4, 0xe4378fb8, 0xb8e46b37
+, 0x5de7789f, 0x9f5d25e7, 0x6eb20fbd, 0xbd6e61b2, 0xef2a6943, 0x43ef862a, 0xa6f135c4, 0xc4a693f1, 0xa8e3da39, 0x39a872e3, 0xa4f7c631, 0x31a462f7, 0x37598ad3, 0xd337bd59, 0x8b8674f2, 0xf28bff86
+, 0x325683d5, 0xd532b156, 0x43c54e8b, 0x8b430dc5, 0x59eb856e, 0x6e59dceb, 0xb7c218da, 0xdab7afc2, 0x8c8f8e01, 0x18c028f, 0x64ac1db1, 0xb16479ac, 0xd26df19c, 0x9cd2236d, 0xe03b7249, 0x49e0923b
+, 0xb4c71fd8, 0xd8b4abc7, 0xfa15b9ac, 0xacfa4315, 0x709faf3, 0xf307fd09, 0x256fa0cf, 0xcf25856f, 0xafea20ca, 0xcaaf8fea, 0x8e897df4, 0xf48ef389, 0xe9206747, 0x47e98e20, 0x18283810, 0x10182028
+, 0xd5640b6f, 0x6fd5de64, 0x888373f0, 0xf088fb83, 0x6fb1fb4a, 0x4a6f94b1, 0x7296ca5c, 0x5c72b896, 0x246c5438, 0x3824706c, 0xf1085f57, 0x57f1ae08, 0xc7522173, 0x73c7e652, 0x51f36497, 0x975135f3
+, 0x2365aecb, 0xcb238d65, 0x7c8425a1, 0xa17c5984, 0x9cbf57e8, 0xe89ccbbf, 0x21635d3e, 0x3e217c63, 0xdd7cea96, 0x96dd377c, 0xdc7f1e61, 0x61dcc27f, 0x86919c0d, 0xd861a91, 0x85949b0f, 0xf851e94
+, 0x90ab4be0, 0xe090dbab, 0x42c6ba7c, 0x7c42f8c6, 0xc4572671, 0x71c4e257, 0xaae529cc, 0xccaa83e5, 0xd873e390, 0x90d83b73, 0x50f0906, 0x6050c0f, 0x103f4f7, 0xf701f503, 0x12362a1c, 0x1c123836
+, 0xa3fe3cc2, 0xc2a39ffe, 0x5fe18b6a, 0x6a5fd4e1, 0xf910beae, 0xaef94710, 0xd06b0269, 0x69d0d26b, 0x91a8bf17, 0x17912ea8, 0x58e87199, 0x995829e8, 0x2769533a, 0x3a277469, 0xb9d0f727, 0x27b94ed0
+, 0x384891d9, 0xd938a948, 0x1335deeb, 0xeb13cd35, 0xb3cee52b, 0x2bb356ce, 0x33557722, 0x22334455, 0xbbd604d2, 0xd2bbbfd6, 0x709039a9, 0xa9704990, 0x89808707, 0x7890e80, 0xa7f2c133, 0x33a766f2
+, 0xb6c1ec2d, 0x2db65ac1, 0x22665a3c, 0x3c227866, 0x92adb815, 0x15922aad, 0x2060a9c9, 0xc9208960, 0x49db5c87, 0x874915db, 0xff1ab0aa, 0xaaff4f1a, 0x7888d850, 0x5078a088, 0x7a8e2ba5, 0xa57a518e
+, 0x8f8a8903, 0x38f068a, 0xf8134a59, 0x59f8b213, 0x809b9209, 0x980129b, 0x1739231a, 0x1a173439, 0xda751065, 0x65daca75, 0x315384d7, 0xd731b553, 0xc651d584, 0x84c61351, 0xb8d303d0, 0xd0b8bbd3
+, 0xc35edc82, 0x82c31f5e, 0xb0cbe229, 0x29b052cb, 0x7799c35a, 0x5a77b499, 0x11332d1e, 0x1e113c33, 0xcb463d7b, 0x7bcbf646, 0xfc1fb7a8, 0xa8fc4b1f, 0xd6610c6d, 0x6dd6da61, 0x3a4e622c, 0x2c3a584e};
+
+#endif /* __tables_h */
diff --git a/crypt/monero_crypto/hash-extra-blake.c b/crypt/monero_crypto/hash-extra-blake.c
new file mode 100644
index 0000000000..2364798809
--- /dev/null
+++ b/crypt/monero_crypto/hash-extra-blake.c
@@ -0,0 +1,38 @@
+// 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
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "blake256.h"
+
+void hash_extra_blake(const void *data, size_t length, char *hash) {
+  blake256_hash((uint8_t*)hash, data, length);
+}
diff --git a/crypt/monero_crypto/hash-extra-groestl.c b/crypt/monero_crypto/hash-extra-groestl.c
new file mode 100644
index 0000000000..b150753060
--- /dev/null
+++ b/crypt/monero_crypto/hash-extra-groestl.c
@@ -0,0 +1,38 @@
+// 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
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "groestl.h"
+
+void hash_extra_groestl(const void *data, size_t length, char *hash) {
+  groestl(data, length * 8, (uint8_t*)hash);
+}
diff --git a/crypt/monero_crypto/hash-extra-jh.c b/crypt/monero_crypto/hash-extra-jh.c
new file mode 100644
index 0000000000..8950687d3c
--- /dev/null
+++ b/crypt/monero_crypto/hash-extra-jh.c
@@ -0,0 +1,42 @@
+// 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
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "jh.h"
+#include "hash-ops.h"
+
+void hash_extra_jh(const void *data, size_t length, char *hash) {
+  int r = jh_hash(HASH_SIZE * 8, data, 8 * length, (uint8_t*)hash);
+  assert(SUCCESS == r);
+}
diff --git a/crypt/monero_crypto/hash-extra-skein.c b/crypt/monero_crypto/hash-extra-skein.c
new file mode 100644
index 0000000000..e63e7da20d
--- /dev/null
+++ b/crypt/monero_crypto/hash-extra-skein.c
@@ -0,0 +1,40 @@
+// 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
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "hash-ops.h"
+#include "skein.h"
+
+void hash_extra_skein(const void *data, size_t length, char *hash) {
+  int r = skein_hash(8 * HASH_SIZE, data, 8 * length, (uint8_t*)hash);
+  assert(SKEIN_SUCCESS == r);
+}
diff --git a/crypt/monero_crypto/hash-ops.h b/crypt/monero_crypto/hash-ops.h
new file mode 100644
index 0000000000..6e3a5c6c9b
--- /dev/null
+++ b/crypt/monero_crypto/hash-ops.h
@@ -0,0 +1,89 @@
+// 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
+
+#pragma once
+
+#if !defined(__cplusplus)
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "common/int-util.h"
+#include "warnings.h"
+
+static inline void *padd(void *p, size_t i) {
+  return (char *) p + i;
+}
+
+static inline const void *cpadd(const void *p, size_t i) {
+  return (const char *) p + i;
+}
+
+PUSH_WARNINGS
+DISABLE_VS_WARNINGS(4267)
+static_assert(sizeof(size_t) == 4 || sizeof(size_t) == 8, "size_t must be 4 or 8 bytes long");
+static inline void place_length(uint8_t *buffer, size_t bufsize, size_t length) {
+  if (sizeof(size_t) == 4) {
+    *(uint32_t *) padd(buffer, bufsize - 4) = swap32be(length);
+  } else {
+    *(uint64_t *) padd(buffer, bufsize - 8) = swap64be(length);
+  }
+}
+POP_WARNINGS
+
+#pragma pack(push, 1)
+union hash_state {
+  uint8_t b[200];
+  uint64_t w[25];
+};
+#pragma pack(pop)
+static_assert(sizeof(union hash_state) == 200, "Invalid structure size");
+
+void hash_permutation(union hash_state *state);
+void hash_process(union hash_state *state, const uint8_t *buf, size_t count);
+
+#endif
+
+enum {
+  HASH_SIZE = 32,
+  HASH_DATA_AREA = 136
+};
+
+void cn_fast_hash(const void *data, size_t length, char *hash);
+void cn_slow_hash(const void *data, size_t length, char *hash);
+
+void hash_extra_blake(const void *data, size_t length, char *hash);
+void hash_extra_groestl(const void *data, size_t length, char *hash);
+void hash_extra_jh(const void *data, size_t length, char *hash);
+void hash_extra_skein(const void *data, size_t length, char *hash);
+
+void tree_hash(const char (*hashes)[HASH_SIZE], size_t count, char *root_hash);
diff --git a/crypt/monero_crypto/hash.c b/crypt/monero_crypto/hash.c
new file mode 100644
index 0000000000..ed95391d88
--- /dev/null
+++ b/crypt/monero_crypto/hash.c
@@ -0,0 +1,50 @@
+// 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
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "hash-ops.h"
+#include "keccak.h"
+
+void hash_permutation(union hash_state *state) {
+  keccakf((uint64_t*)state, 24);
+}
+
+void hash_process(union hash_state *state, const uint8_t *buf, size_t count) {
+  keccak1600(buf, count, (uint8_t*)state);
+}
+
+void cn_fast_hash(const void *data, size_t length, char *hash) {
+  union hash_state state;
+  hash_process(&state, data, length);
+  memcpy(hash, &state, HASH_SIZE);
+}
diff --git a/crypt/monero_crypto/hash.h b/crypt/monero_crypto/hash.h
new file mode 100644
index 0000000000..610b4502f1
--- /dev/null
+++ b/crypt/monero_crypto/hash.h
@@ -0,0 +1,94 @@
+// 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
+
+#pragma once
+
+#include <stddef.h>
+#include <iostream>
+#include <boost/utility/value_init.hpp>
+
+#include "common/pod-class.h"
+#include "generic-ops.h"
+#include "hex.h"
+#include "span.h"
+
+namespace crypto {
+
+  extern "C" {
+#include "hash-ops.h"
+  }
+
+#pragma pack(push, 1)
+  POD_CLASS hash {
+    char data[HASH_SIZE];
+  };
+  POD_CLASS hash8 {
+    char data[8];
+  };
+#pragma pack(pop)
+
+  static_assert(sizeof(hash) == HASH_SIZE, "Invalid structure size");
+  static_assert(sizeof(hash8) == 8, "Invalid structure size");
+
+  /*
+    Cryptonight hash functions
+  */
+
+  inline void cn_fast_hash(const void *data, std::size_t length, hash &hash) {
+    cn_fast_hash(data, length, reinterpret_cast<char *>(&hash));
+  }
+
+  inline hash cn_fast_hash(const void *data, std::size_t length) {
+    hash h;
+    cn_fast_hash(data, length, reinterpret_cast<char *>(&h));
+    return h;
+  }
+
+  inline void cn_slow_hash(const void *data, std::size_t length, hash &hash) {
+    cn_slow_hash(data, length, reinterpret_cast<char *>(&hash));
+  }
+
+  inline void tree_hash(const hash *hashes, std::size_t count, hash &root_hash) {
+    tree_hash(reinterpret_cast<const char (*)[HASH_SIZE]>(hashes), count, reinterpret_cast<char *>(&root_hash));
+  }
+
+  inline std::ostream &operator <<(std::ostream &o, const crypto::hash &v) {
+    epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
+  }
+  inline std::ostream &operator <<(std::ostream &o, const crypto::hash8 &v) {
+    epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
+  }
+
+  const static crypto::hash null_hash = boost::value_initialized<crypto::hash>();
+  const static crypto::hash8 null_hash8 = boost::value_initialized<crypto::hash8>();
+}
+
+CRYPTO_MAKE_HASHABLE(hash)
+CRYPTO_MAKE_COMPARABLE(hash8)
diff --git a/crypt/monero_crypto/initializer.h b/crypt/monero_crypto/initializer.h
new file mode 100644
index 0000000000..eb1d1c069a
--- /dev/null
+++ b/crypt/monero_crypto/initializer.h
@@ -0,0 +1,63 @@
+// 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
+
+#pragma once
+
+#if defined(__GNUC__)
+#if defined(__sun) && defined(__SVR4)
+#define INITIALIZER(name) __attribute__((constructor)) static void name(void)
+#define FINALIZER(name) __attribute__((destructor)) static void name(void)
+#else
+#define INITIALIZER(name) __attribute__((constructor(101))) static void name(void)
+#define FINALIZER(name) __attribute__((destructor(101))) static void name(void)
+#endif
+#define REGISTER_FINALIZER(name) ((void) 0)
+
+#elif defined(_MSC_VER)
+#include <assert.h>
+#include <stdlib.h>
+// http://stackoverflow.com/questions/1113409/attribute-constructor-equivalent-in-vc
+// http://msdn.microsoft.com/en-us/library/bb918180.aspx
+#pragma section(".CRT$XCT", read)
+#define INITIALIZER(name) \
+  static void __cdecl name(void); \
+  __declspec(allocate(".CRT$XCT")) void (__cdecl *const _##name)(void) = &name; \
+  static void __cdecl name(void)
+#define FINALIZER(name) \
+  static void __cdecl name(void)
+#define REGISTER_FINALIZER(name) \
+  do { \
+    int _res = atexit(name); \
+    assert(_res == 0); \
+  } while (0);
+
+#else
+#error Unsupported compiler
+#endif
diff --git a/crypt/hash/jh.c b/crypt/monero_crypto/jh.c
similarity index 100%
rename from crypt/hash/jh.c
rename to crypt/monero_crypto/jh.c
diff --git a/crypt/hash/jh.h b/crypt/monero_crypto/jh.h
similarity index 100%
rename from crypt/hash/jh.h
rename to crypt/monero_crypto/jh.h
diff --git a/crypt/hash/keccak.c b/crypt/monero_crypto/keccak.c
similarity index 100%
rename from crypt/hash/keccak.c
rename to crypt/monero_crypto/keccak.c
diff --git a/crypt/hash/keccak.h b/crypt/monero_crypto/keccak.h
similarity index 100%
rename from crypt/hash/keccak.h
rename to crypt/monero_crypto/keccak.h
diff --git a/crypt/monero_crypto/oaes_config.h b/crypt/monero_crypto/oaes_config.h
new file mode 100644
index 0000000000..3fc0e1be5c
--- /dev/null
+++ b/crypt/monero_crypto/oaes_config.h
@@ -0,0 +1,50 @@
+/* 
+ * ---------------------------------------------------------------------------
+ * OpenAES License
+ * ---------------------------------------------------------------------------
+ * Copyright (c) 2012, Nabil S. Al Ramli, www.nalramli.com
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *   - Redistributions of source code must retain the above copyright notice,
+ *     this list of conditions and the following disclaimer.
+ *   - 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.
+ * 
+ * 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.
+ * ---------------------------------------------------------------------------
+ */
+
+#ifndef _OAES_CONFIG_H
+#define _OAES_CONFIG_H
+
+#ifdef __cplusplus 
+extern "C" {
+#endif
+
+//#ifndef OAES_HAVE_ISAAC
+//#define OAES_HAVE_ISAAC 1
+//#endif // OAES_HAVE_ISAAC
+
+//#ifndef OAES_DEBUG
+//#define OAES_DEBUG 0
+//#endif // OAES_DEBUG
+
+#ifdef __cplusplus 
+}
+#endif
+
+#endif // _OAES_CONFIG_H
diff --git a/crypt/oaes_lib.c b/crypt/monero_crypto/oaes_lib.c
similarity index 100%
rename from crypt/oaes_lib.c
rename to crypt/monero_crypto/oaes_lib.c
diff --git a/crypt/oaes_lib.h b/crypt/monero_crypto/oaes_lib.h
similarity index 100%
rename from crypt/oaes_lib.h
rename to crypt/monero_crypto/oaes_lib.h
diff --git a/crypt/monero_crypto/random.c b/crypt/monero_crypto/random.c
new file mode 100644
index 0000000000..691c31f624
--- /dev/null
+++ b/crypt/monero_crypto/random.c
@@ -0,0 +1,143 @@
+// 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
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "hash-ops.h"
+#include "initializer.h"
+#include "random.h"
+
+static void generate_system_random_bytes(size_t n, void *result);
+
+#if defined(_WIN32)
+
+#include <windows.h>
+#include <wincrypt.h>
+
+static void generate_system_random_bytes(size_t n, void *result) {
+  HCRYPTPROV prov;
+#define must_succeed(x) do if (!(x)) abort(); while (0)
+  must_succeed(CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT));
+  must_succeed(CryptGenRandom(prov, (DWORD)n, result));
+  must_succeed(CryptReleaseContext(prov, 0));
+#undef must_succeed
+}
+
+#else
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+static void generate_system_random_bytes(size_t n, void *result) {
+  int fd;
+  if ((fd = open("/dev/urandom", O_RDONLY | O_NOCTTY | O_CLOEXEC)) < 0) {
+    err(EXIT_FAILURE, "open /dev/urandom");
+  }
+  for (;;) {
+    ssize_t res = read(fd, result, n);
+    if ((size_t) res == n) {
+      break;
+    }
+    if (res < 0) {
+      if (errno != EINTR) {
+        err(EXIT_FAILURE, "read /dev/urandom");
+      }
+    } else if (res == 0) {
+      errx(EXIT_FAILURE, "read /dev/urandom: end of file");
+    } else {
+      result = padd(result, (size_t) res);
+      n -= (size_t) res;
+    }
+  }
+  if (close(fd) < 0) {
+    err(EXIT_FAILURE, "close /dev/urandom");
+  }
+}
+
+#endif
+
+static union hash_state state;
+
+#if !defined(NDEBUG)
+static volatile int curstate; /* To catch thread safety problems. */
+#endif
+
+FINALIZER(deinit_random) {
+#if !defined(NDEBUG)
+  assert(curstate == 1);
+  curstate = 0;
+#endif
+  memset(&state, 0, sizeof(union hash_state));
+}
+
+INITIALIZER(init_random) {
+  generate_system_random_bytes(32, &state);
+  REGISTER_FINALIZER(deinit_random);
+#if !defined(NDEBUG)
+  assert(curstate == 0);
+  curstate = 1;
+#endif
+}
+
+void generate_random_bytes_not_thread_safe(size_t n, void *result) {
+#if !defined(NDEBUG)
+  assert(curstate == 1);
+  curstate = 2;
+#endif
+  if (n == 0) {
+#if !defined(NDEBUG)
+    assert(curstate == 2);
+    curstate = 1;
+#endif
+    return;
+  }
+  for (;;) {
+    hash_permutation(&state);
+    if (n <= HASH_DATA_AREA) {
+      memcpy(result, &state, n);
+#if !defined(NDEBUG)
+      assert(curstate == 2);
+      curstate = 1;
+#endif
+      return;
+    } else {
+      memcpy(result, &state, HASH_DATA_AREA);
+      result = padd(result, HASH_DATA_AREA);
+      n -= HASH_DATA_AREA;
+    }
+  }
+}
diff --git a/crypt/monero_crypto/random.h b/crypt/monero_crypto/random.h
new file mode 100644
index 0000000000..75d23fd04d
--- /dev/null
+++ b/crypt/monero_crypto/random.h
@@ -0,0 +1,35 @@
+// 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
+
+#pragma once
+
+#include <stddef.h>
+
+void generate_random_bytes_not_thread_safe(size_t n, void *result);
diff --git a/crypt/monero_crypto/skein.c b/crypt/monero_crypto/skein.c
new file mode 100644
index 0000000000..65e4525c33
--- /dev/null
+++ b/crypt/monero_crypto/skein.c
@@ -0,0 +1,2036 @@
+/***********************************************************************
+**
+** Implementation of the Skein hash function.
+**
+** Source code author: Doug Whiting, 2008.
+**
+** This algorithm and source code is released to the public domain.
+** 
+************************************************************************/
+
+#define  SKEIN_PORT_CODE /* instantiate any code in skein_port.h */
+
+#include <stddef.h>                          /* get size_t definition */
+#include <string.h>      /* get the memcpy/memset functions */
+#include "skein.h"       /* get the Skein API definitions   */
+
+#define DISABLE_UNUSED 0
+
+#ifndef SKEIN_256_NIST_MAX_HASHBITS
+#define SKEIN_256_NIST_MAX_HASHBITS (0)
+#endif
+
+#ifndef SKEIN_512_NIST_MAX_HASHBITS
+#define SKEIN_512_NIST_MAX_HASHBITS (512)
+#endif
+
+#define  SKEIN_MODIFIER_WORDS  ( 2)          /* number of modifier (tweak) words */
+
+#define  SKEIN_256_STATE_WORDS ( 4)
+#define  SKEIN_512_STATE_WORDS ( 8)
+#define  SKEIN1024_STATE_WORDS (16)
+#define  SKEIN_MAX_STATE_WORDS (16)
+
+#define  SKEIN_256_STATE_BYTES ( 8*SKEIN_256_STATE_WORDS)
+#define  SKEIN_512_STATE_BYTES ( 8*SKEIN_512_STATE_WORDS)
+#define  SKEIN1024_STATE_BYTES ( 8*SKEIN1024_STATE_WORDS)
+
+#define  SKEIN_256_STATE_BITS  (64*SKEIN_256_STATE_WORDS)
+#define  SKEIN_512_STATE_BITS  (64*SKEIN_512_STATE_WORDS)
+#define  SKEIN1024_STATE_BITS  (64*SKEIN1024_STATE_WORDS)
+
+#define  SKEIN_256_BLOCK_BYTES ( 8*SKEIN_256_STATE_WORDS)
+#define  SKEIN_512_BLOCK_BYTES ( 8*SKEIN_512_STATE_WORDS)
+#define  SKEIN1024_BLOCK_BYTES ( 8*SKEIN1024_STATE_WORDS)
+
+#define SKEIN_RND_SPECIAL       (1000u)
+#define SKEIN_RND_KEY_INITIAL   (SKEIN_RND_SPECIAL+0u)
+#define SKEIN_RND_KEY_INJECT    (SKEIN_RND_SPECIAL+1u)
+#define SKEIN_RND_FEED_FWD      (SKEIN_RND_SPECIAL+2u)
+
+typedef struct
+{
+  size_t  hashBitLen;                      /* size of hash result, in bits */
+  size_t  bCnt;                            /* current byte count in buffer b[] */
+  u64b_t  T[SKEIN_MODIFIER_WORDS];         /* tweak words: T[0]=byte cnt, T[1]=flags */
+} Skein_Ctxt_Hdr_t;
+
+typedef struct                               /*  256-bit Skein hash context structure */
+{
+  Skein_Ctxt_Hdr_t h;                      /* common header context variables */
+  u64b_t  X[SKEIN_256_STATE_WORDS];        /* chaining variables */
+  u08b_t  b[SKEIN_256_BLOCK_BYTES];        /* partial block buffer (8-byte aligned) */
+} Skein_256_Ctxt_t;
+
+typedef struct                               /*  512-bit Skein hash context structure */
+{
+  Skein_Ctxt_Hdr_t h;                      /* common header context variables */
+  u64b_t  X[SKEIN_512_STATE_WORDS];        /* chaining variables */
+  u08b_t  b[SKEIN_512_BLOCK_BYTES];        /* partial block buffer (8-byte aligned) */
+} Skein_512_Ctxt_t;
+
+typedef struct                               /* 1024-bit Skein hash context structure */
+{
+  Skein_Ctxt_Hdr_t h;                      /* common header context variables */
+  u64b_t  X[SKEIN1024_STATE_WORDS];        /* chaining variables */
+  u08b_t  b[SKEIN1024_BLOCK_BYTES];        /* partial block buffer (8-byte aligned) */
+} Skein1024_Ctxt_t;
+
+/*   Skein APIs for (incremental) "straight hashing" */
+#if SKEIN_256_NIST_MAX_HASHBITS
+static int  Skein_256_Init  (Skein_256_Ctxt_t *ctx, size_t hashBitLen);
+#endif
+static int  Skein_512_Init  (Skein_512_Ctxt_t *ctx, size_t hashBitLen);
+static int  Skein1024_Init  (Skein1024_Ctxt_t *ctx, size_t hashBitLen);
+
+static int  Skein_256_Update(Skein_256_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt);
+static int  Skein_512_Update(Skein_512_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt);
+static int  Skein1024_Update(Skein1024_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt);
+
+static int  Skein_256_Final (Skein_256_Ctxt_t *ctx, u08b_t * hashVal);
+static int  Skein_512_Final (Skein_512_Ctxt_t *ctx, u08b_t * hashVal);
+static int  Skein1024_Final (Skein1024_Ctxt_t *ctx, u08b_t * hashVal);
+
+/*
+**   Skein APIs for "extended" initialization: MAC keys, tree hashing.
+**   After an InitExt() call, just use Update/Final calls as with Init().
+**
+**   Notes: Same parameters as _Init() calls, plus treeInfo/key/keyBytes.
+**          When keyBytes == 0 and treeInfo == SKEIN_SEQUENTIAL, 
+**              the results of InitExt() are identical to calling Init().
+**          The function Init() may be called once to "precompute" the IV for
+**              a given hashBitLen value, then by saving a copy of the context
+**              the IV computation may be avoided in later calls.
+**          Similarly, the function InitExt() may be called once per MAC key 
+**              to precompute the MAC IV, then a copy of the context saved and
+**              reused for each new MAC computation.
+**/
+#if 0
+static int  Skein_256_InitExt(Skein_256_Ctxt_t *ctx, size_t hashBitLen, u64b_t treeInfo, const u08b_t *key, size_t keyBytes);
+static int  Skein_512_InitExt(Skein_512_Ctxt_t *ctx, size_t hashBitLen, u64b_t treeInfo, const u08b_t *key, size_t keyBytes);
+static int  Skein1024_InitExt(Skein1024_Ctxt_t *ctx, size_t hashBitLen, u64b_t treeInfo, const u08b_t *key, size_t keyBytes);
+#endif
+
+/*
+**   Skein APIs for MAC and tree hash:
+**      Final_Pad:  pad, do final block, but no OUTPUT type
+**      Output:     do just the output stage
+*/
+#if 0
+static int  Skein_256_Final_Pad(Skein_256_Ctxt_t *ctx, u08b_t * hashVal);
+static int  Skein_512_Final_Pad(Skein_512_Ctxt_t *ctx, u08b_t * hashVal);
+static int  Skein1024_Final_Pad(Skein1024_Ctxt_t *ctx, u08b_t * hashVal);
+#endif
+
+#ifndef SKEIN_TREE_HASH
+#define SKEIN_TREE_HASH (1)
+#endif
+#if 0
+#if  SKEIN_TREE_HASH
+static int  Skein_256_Output   (Skein_256_Ctxt_t *ctx, u08b_t * hashVal);
+static int  Skein_512_Output   (Skein_512_Ctxt_t *ctx, u08b_t * hashVal);
+static int  Skein1024_Output   (Skein1024_Ctxt_t *ctx, u08b_t * hashVal);
+#endif
+#endif
+
+/*****************************************************************
+** "Internal" Skein definitions
+**    -- not needed for sequential hashing API, but will be 
+**           helpful for other uses of Skein (e.g., tree hash mode).
+**    -- included here so that they can be shared between
+**           reference and optimized code.
+******************************************************************/
+
+/* tweak word T[1]: bit field starting positions */
+#define SKEIN_T1_BIT(BIT)       ((BIT) - 64)            /* offset 64 because it's the second word  */
+
+#define SKEIN_T1_POS_TREE_LVL   SKEIN_T1_BIT(112)       /* bits 112..118: level in hash tree       */
+#define SKEIN_T1_POS_BIT_PAD    SKEIN_T1_BIT(119)       /* bit  119     : partial final input byte */
+#define SKEIN_T1_POS_BLK_TYPE   SKEIN_T1_BIT(120)       /* bits 120..125: type field               */
+#define SKEIN_T1_POS_FIRST      SKEIN_T1_BIT(126)       /* bits 126     : first block flag         */
+#define SKEIN_T1_POS_FINAL      SKEIN_T1_BIT(127)       /* bit  127     : final block flag         */
+
+/* tweak word T[1]: flag bit definition(s) */
+#define SKEIN_T1_FLAG_FIRST     (((u64b_t)  1 ) << SKEIN_T1_POS_FIRST)
+#define SKEIN_T1_FLAG_FINAL     (((u64b_t)  1 ) << SKEIN_T1_POS_FINAL)
+#define SKEIN_T1_FLAG_BIT_PAD   (((u64b_t)  1 ) << SKEIN_T1_POS_BIT_PAD)
+
+/* tweak word T[1]: tree level bit field mask */
+#define SKEIN_T1_TREE_LVL_MASK  (((u64b_t)0x7F) << SKEIN_T1_POS_TREE_LVL)
+#define SKEIN_T1_TREE_LEVEL(n)  (((u64b_t) (n)) << SKEIN_T1_POS_TREE_LVL)
+
+/* tweak word T[1]: block type field */
+#define SKEIN_BLK_TYPE_KEY      ( 0)                    /* key, for MAC and KDF */
+#define SKEIN_BLK_TYPE_CFG      ( 4)                    /* configuration block */
+#define SKEIN_BLK_TYPE_PERS     ( 8)                    /* personalization string */
+#define SKEIN_BLK_TYPE_PK       (12)                    /* public key (for digital signature hashing) */
+#define SKEIN_BLK_TYPE_KDF      (16)                    /* key identifier for KDF */
+#define SKEIN_BLK_TYPE_NONCE    (20)                    /* nonce for PRNG */
+#define SKEIN_BLK_TYPE_MSG      (48)                    /* message processing */
+#define SKEIN_BLK_TYPE_OUT      (63)                    /* output stage */
+#define SKEIN_BLK_TYPE_MASK     (63)                    /* bit field mask */
+
+#define SKEIN_T1_BLK_TYPE(T)   (((u64b_t) (SKEIN_BLK_TYPE_##T)) << SKEIN_T1_POS_BLK_TYPE)
+#define SKEIN_T1_BLK_TYPE_KEY   SKEIN_T1_BLK_TYPE(KEY)  /* key, for MAC and KDF */
+#define SKEIN_T1_BLK_TYPE_CFG   SKEIN_T1_BLK_TYPE(CFG)  /* configuration block */
+#define SKEIN_T1_BLK_TYPE_PERS  SKEIN_T1_BLK_TYPE(PERS) /* personalization string */
+#define SKEIN_T1_BLK_TYPE_PK    SKEIN_T1_BLK_TYPE(PK)   /* public key (for digital signature hashing) */
+#define SKEIN_T1_BLK_TYPE_KDF   SKEIN_T1_BLK_TYPE(KDF)  /* key identifier for KDF */
+#define SKEIN_T1_BLK_TYPE_NONCE SKEIN_T1_BLK_TYPE(NONCE)/* nonce for PRNG */
+#define SKEIN_T1_BLK_TYPE_MSG   SKEIN_T1_BLK_TYPE(MSG)  /* message processing */
+#define SKEIN_T1_BLK_TYPE_OUT   SKEIN_T1_BLK_TYPE(OUT)  /* output stage */
+#define SKEIN_T1_BLK_TYPE_MASK  SKEIN_T1_BLK_TYPE(MASK) /* field bit mask */
+
+#define SKEIN_T1_BLK_TYPE_CFG_FINAL       (SKEIN_T1_BLK_TYPE_CFG | SKEIN_T1_FLAG_FINAL)
+#define SKEIN_T1_BLK_TYPE_OUT_FINAL       (SKEIN_T1_BLK_TYPE_OUT | SKEIN_T1_FLAG_FINAL)
+
+#define SKEIN_VERSION           (1)
+
+#ifndef SKEIN_ID_STRING_LE      /* allow compile-time personalization */
+#define SKEIN_ID_STRING_LE      (0x33414853)            /* "SHA3" (little-endian)*/
+#endif
+
+#define SKEIN_MK_64(hi32,lo32)  ((lo32) + (((u64b_t) (hi32)) << 32))
+#define SKEIN_SCHEMA_VER        SKEIN_MK_64(SKEIN_VERSION,SKEIN_ID_STRING_LE)
+#define SKEIN_KS_PARITY         SKEIN_MK_64(0x1BD11BDA,0xA9FC1A22)
+
+#define SKEIN_CFG_STR_LEN       (4*8)
+
+/* bit field definitions in config block treeInfo word */
+#define SKEIN_CFG_TREE_LEAF_SIZE_POS  ( 0)
+#define SKEIN_CFG_TREE_NODE_SIZE_POS  ( 8)
+#define SKEIN_CFG_TREE_MAX_LEVEL_POS  (16)
+
+#define SKEIN_CFG_TREE_LEAF_SIZE_MSK  (((u64b_t) 0xFF) << SKEIN_CFG_TREE_LEAF_SIZE_POS)
+#define SKEIN_CFG_TREE_NODE_SIZE_MSK  (((u64b_t) 0xFF) << SKEIN_CFG_TREE_NODE_SIZE_POS)
+#define SKEIN_CFG_TREE_MAX_LEVEL_MSK  (((u64b_t) 0xFF) << SKEIN_CFG_TREE_MAX_LEVEL_POS)
+
+#define SKEIN_CFG_TREE_INFO(leaf,node,maxLvl)                   \
+  ( (((u64b_t)(leaf  )) << SKEIN_CFG_TREE_LEAF_SIZE_POS) |    \
+  (((u64b_t)(node  )) << SKEIN_CFG_TREE_NODE_SIZE_POS) |    \
+  (((u64b_t)(maxLvl)) << SKEIN_CFG_TREE_MAX_LEVEL_POS) )
+
+#define SKEIN_CFG_TREE_INFO_SEQUENTIAL SKEIN_CFG_TREE_INFO(0,0,0) /* use as treeInfo in InitExt() call for sequential processing */
+
+/*
+**   Skein macros for getting/setting tweak words, etc.
+**   These are useful for partial input bytes, hash tree init/update, etc.
+**/
+#define Skein_Get_Tweak(ctxPtr,TWK_NUM)         ((ctxPtr)->h.T[TWK_NUM])
+#define Skein_Set_Tweak(ctxPtr,TWK_NUM,tVal)    {(ctxPtr)->h.T[TWK_NUM] = (tVal);}
+
+#define Skein_Get_T0(ctxPtr)    Skein_Get_Tweak(ctxPtr,0)
+#define Skein_Get_T1(ctxPtr)    Skein_Get_Tweak(ctxPtr,1)
+#define Skein_Set_T0(ctxPtr,T0) Skein_Set_Tweak(ctxPtr,0,T0)
+#define Skein_Set_T1(ctxPtr,T1) Skein_Set_Tweak(ctxPtr,1,T1)
+
+/* set both tweak words at once */
+#define Skein_Set_T0_T1(ctxPtr,T0,T1)           \
+{                                           \
+  Skein_Set_T0(ctxPtr,(T0));                  \
+  Skein_Set_T1(ctxPtr,(T1));                  \
+}
+
+#define Skein_Set_Type(ctxPtr,BLK_TYPE)         \
+  Skein_Set_T1(ctxPtr,SKEIN_T1_BLK_TYPE_##BLK_TYPE)
+
+/* set up for starting with a new type: h.T[0]=0; h.T[1] = NEW_TYPE; h.bCnt=0; */
+#define Skein_Start_New_Type(ctxPtr,BLK_TYPE)   \
+{ Skein_Set_T0_T1(ctxPtr,0,SKEIN_T1_FLAG_FIRST | SKEIN_T1_BLK_TYPE_##BLK_TYPE); (ctxPtr)->h.bCnt=0; }
+
+#define Skein_Clear_First_Flag(hdr)      { (hdr).T[1] &= ~SKEIN_T1_FLAG_FIRST;       }
+#define Skein_Set_Bit_Pad_Flag(hdr)      { (hdr).T[1] |=  SKEIN_T1_FLAG_BIT_PAD;     }
+
+#define Skein_Set_Tree_Level(hdr,height) { (hdr).T[1] |= SKEIN_T1_TREE_LEVEL(height);}
+
+/*****************************************************************
+** "Internal" Skein definitions for debugging and error checking
+******************************************************************/
+#define Skein_Show_Block(bits,ctx,X,blkPtr,wPtr,ksEvenPtr,ksOddPtr)
+#define Skein_Show_Round(bits,ctx,r,X)
+#define Skein_Show_R_Ptr(bits,ctx,r,X_ptr)
+#define Skein_Show_Final(bits,ctx,cnt,outPtr)
+#define Skein_Show_Key(bits,ctx,key,keyBytes)
+
+
+#ifndef SKEIN_ERR_CHECK        /* run-time checks (e.g., bad params, uninitialized context)? */
+#define Skein_Assert(x,retCode)/* default: ignore all Asserts, for performance */
+#define Skein_assert(x)
+#elif   defined(SKEIN_ASSERT)
+#include <assert.h>     
+#define Skein_Assert(x,retCode) assert(x) 
+#define Skein_assert(x)         assert(x) 
+#else
+#include <assert.h>     
+#define Skein_Assert(x,retCode) { if (!(x)) return retCode; } /*  caller  error */
+#define Skein_assert(x)         assert(x)                     /* internal error */
+#endif
+
+/*****************************************************************
+** Skein block function constants (shared across Ref and Opt code)
+******************************************************************/
+enum    
+{   
+  /* Skein_256 round rotation constants */
+  R_256_0_0=14, R_256_0_1=16,
+  R_256_1_0=52, R_256_1_1=57,
+  R_256_2_0=23, R_256_2_1=40,
+  R_256_3_0= 5, R_256_3_1=37,
+  R_256_4_0=25, R_256_4_1=33,
+  R_256_5_0=46, R_256_5_1=12,
+  R_256_6_0=58, R_256_6_1=22,
+  R_256_7_0=32, R_256_7_1=32,
+
+  /* Skein_512 round rotation constants */
+  R_512_0_0=46, R_512_0_1=36, R_512_0_2=19, R_512_0_3=37,
+  R_512_1_0=33, R_512_1_1=27, R_512_1_2=14, R_512_1_3=42,
+  R_512_2_0=17, R_512_2_1=49, R_512_2_2=36, R_512_2_3=39,
+  R_512_3_0=44, R_512_3_1= 9, R_512_3_2=54, R_512_3_3=56,
+  R_512_4_0=39, R_512_4_1=30, R_512_4_2=34, R_512_4_3=24,
+  R_512_5_0=13, R_512_5_1=50, R_512_5_2=10, R_512_5_3=17,
+  R_512_6_0=25, R_512_6_1=29, R_512_6_2=39, R_512_6_3=43,
+  R_512_7_0= 8, R_512_7_1=35, R_512_7_2=56, R_512_7_3=22,
+
+  /* Skein1024 round rotation constants */
+  R1024_0_0=24, R1024_0_1=13, R1024_0_2= 8, R1024_0_3=47, R1024_0_4= 8, R1024_0_5=17, R1024_0_6=22, R1024_0_7=37,
+  R1024_1_0=38, R1024_1_1=19, R1024_1_2=10, R1024_1_3=55, R1024_1_4=49, R1024_1_5=18, R1024_1_6=23, R1024_1_7=52,
+  R1024_2_0=33, R1024_2_1= 4, R1024_2_2=51, R1024_2_3=13, R1024_2_4=34, R1024_2_5=41, R1024_2_6=59, R1024_2_7=17,
+  R1024_3_0= 5, R1024_3_1=20, R1024_3_2=48, R1024_3_3=41, R1024_3_4=47, R1024_3_5=28, R1024_3_6=16, R1024_3_7=25,
+  R1024_4_0=41, R1024_4_1= 9, R1024_4_2=37, R1024_4_3=31, R1024_4_4=12, R1024_4_5=47, R1024_4_6=44, R1024_4_7=30,
+  R1024_5_0=16, R1024_5_1=34, R1024_5_2=56, R1024_5_3=51, R1024_5_4= 4, R1024_5_5=53, R1024_5_6=42, R1024_5_7=41,
+  R1024_6_0=31, R1024_6_1=44, R1024_6_2=47, R1024_6_3=46, R1024_6_4=19, R1024_6_5=42, R1024_6_6=44, R1024_6_7=25,
+  R1024_7_0= 9, R1024_7_1=48, R1024_7_2=35, R1024_7_3=52, R1024_7_4=23, R1024_7_5=31, R1024_7_6=37, R1024_7_7=20
+};
+
+#ifndef SKEIN_ROUNDS
+#define SKEIN_256_ROUNDS_TOTAL (72)          /* number of rounds for the different block sizes */
+#define SKEIN_512_ROUNDS_TOTAL (72)
+#define SKEIN1024_ROUNDS_TOTAL (80)
+#else                                        /* allow command-line define in range 8*(5..14)   */
+#define SKEIN_256_ROUNDS_TOTAL (8*((((SKEIN_ROUNDS/100) + 5) % 10) + 5))
+#define SKEIN_512_ROUNDS_TOTAL (8*((((SKEIN_ROUNDS/ 10) + 5) % 10) + 5))
+#define SKEIN1024_ROUNDS_TOTAL (8*((((SKEIN_ROUNDS    ) + 5) % 10) + 5))
+#endif
+
+
+/*
+***************** Pre-computed Skein IVs *******************
+**
+** NOTE: these values are not "magic" constants, but
+** are generated using the Threefish block function.
+** They are pre-computed here only for speed; i.e., to
+** avoid the need for a Threefish call during Init().
+**
+** The IV for any fixed hash length may be pre-computed.
+** Only the most common values are included here.
+**
+************************************************************
+**/
+
+#define MK_64 SKEIN_MK_64
+
+/* blkSize =  256 bits. hashSize =  128 bits */
+const u64b_t SKEIN_256_IV_128[] =
+    {
+    MK_64(0xE1111906,0x964D7260),
+    MK_64(0x883DAAA7,0x7C8D811C),
+    MK_64(0x10080DF4,0x91960F7A),
+    MK_64(0xCCF7DDE5,0xB45BC1C2)
+    };
+
+/* blkSize =  256 bits. hashSize =  160 bits */
+const u64b_t SKEIN_256_IV_160[] =
+    {
+    MK_64(0x14202314,0x72825E98),
+    MK_64(0x2AC4E9A2,0x5A77E590),
+    MK_64(0xD47A5856,0x8838D63E),
+    MK_64(0x2DD2E496,0x8586AB7D)
+    };
+
+/* blkSize =  256 bits. hashSize =  224 bits */
+const u64b_t SKEIN_256_IV_224[] =
+    {
+    MK_64(0xC6098A8C,0x9AE5EA0B),
+    MK_64(0x876D5686,0x08C5191C),
+    MK_64(0x99CB88D7,0xD7F53884),
+    MK_64(0x384BDDB1,0xAEDDB5DE)
+    };
+
+/* blkSize =  256 bits. hashSize =  256 bits */
+const u64b_t SKEIN_256_IV_256[] =
+    {
+    MK_64(0xFC9DA860,0xD048B449),
+    MK_64(0x2FCA6647,0x9FA7D833),
+    MK_64(0xB33BC389,0x6656840F),
+    MK_64(0x6A54E920,0xFDE8DA69)
+    };
+
+/* blkSize =  512 bits. hashSize =  128 bits */
+const u64b_t SKEIN_512_IV_128[] =
+    {
+    MK_64(0xA8BC7BF3,0x6FBF9F52),
+    MK_64(0x1E9872CE,0xBD1AF0AA),
+    MK_64(0x309B1790,0xB32190D3),
+    MK_64(0xBCFBB854,0x3F94805C),
+    MK_64(0x0DA61BCD,0x6E31B11B),
+    MK_64(0x1A18EBEA,0xD46A32E3),
+    MK_64(0xA2CC5B18,0xCE84AA82),
+    MK_64(0x6982AB28,0x9D46982D)
+    };
+
+/* blkSize =  512 bits. hashSize =  160 bits */
+const u64b_t SKEIN_512_IV_160[] =
+    {
+    MK_64(0x28B81A2A,0xE013BD91),
+    MK_64(0xC2F11668,0xB5BDF78F),
+    MK_64(0x1760D8F3,0xF6A56F12),
+    MK_64(0x4FB74758,0x8239904F),
+    MK_64(0x21EDE07F,0x7EAF5056),
+    MK_64(0xD908922E,0x63ED70B8),
+    MK_64(0xB8EC76FF,0xECCB52FA),
+    MK_64(0x01A47BB8,0xA3F27A6E)
+    };
+
+/* blkSize =  512 bits. hashSize =  224 bits */
+const u64b_t SKEIN_512_IV_224[] =
+    {
+    MK_64(0xCCD06162,0x48677224),
+    MK_64(0xCBA65CF3,0xA92339EF),
+    MK_64(0x8CCD69D6,0x52FF4B64),
+    MK_64(0x398AED7B,0x3AB890B4),
+    MK_64(0x0F59D1B1,0x457D2BD0),
+    MK_64(0x6776FE65,0x75D4EB3D),
+    MK_64(0x99FBC70E,0x997413E9),
+    MK_64(0x9E2CFCCF,0xE1C41EF7)
+    };
+
+/* blkSize =  512 bits. hashSize =  256 bits */
+const u64b_t SKEIN_512_IV_256[] =
+    {
+    MK_64(0xCCD044A1,0x2FDB3E13),
+    MK_64(0xE8359030,0x1A79A9EB),
+    MK_64(0x55AEA061,0x4F816E6F),
+    MK_64(0x2A2767A4,0xAE9B94DB),
+    MK_64(0xEC06025E,0x74DD7683),
+    MK_64(0xE7A436CD,0xC4746251),
+    MK_64(0xC36FBAF9,0x393AD185),
+    MK_64(0x3EEDBA18,0x33EDFC13)
+    };
+
+/* blkSize =  512 bits. hashSize =  384 bits */
+const u64b_t SKEIN_512_IV_384[] =
+    {
+    MK_64(0xA3F6C6BF,0x3A75EF5F),
+    MK_64(0xB0FEF9CC,0xFD84FAA4),
+    MK_64(0x9D77DD66,0x3D770CFE),
+    MK_64(0xD798CBF3,0xB468FDDA),
+    MK_64(0x1BC4A666,0x8A0E4465),
+    MK_64(0x7ED7D434,0xE5807407),
+    MK_64(0x548FC1AC,0xD4EC44D6),
+    MK_64(0x266E1754,0x6AA18FF8)
+    };
+
+/* blkSize =  512 bits. hashSize =  512 bits */
+const u64b_t SKEIN_512_IV_512[] =
+    {
+    MK_64(0x4903ADFF,0x749C51CE),
+    MK_64(0x0D95DE39,0x9746DF03),
+    MK_64(0x8FD19341,0x27C79BCE),
+    MK_64(0x9A255629,0xFF352CB1),
+    MK_64(0x5DB62599,0xDF6CA7B0),
+    MK_64(0xEABE394C,0xA9D5C3F4),
+    MK_64(0x991112C7,0x1A75B523),
+    MK_64(0xAE18A40B,0x660FCC33)
+    };
+
+/* blkSize = 1024 bits. hashSize =  384 bits */
+const u64b_t SKEIN1024_IV_384[] =
+    {
+    MK_64(0x5102B6B8,0xC1894A35),
+    MK_64(0xFEEBC9E3,0xFE8AF11A),
+    MK_64(0x0C807F06,0xE32BED71),
+    MK_64(0x60C13A52,0xB41A91F6),
+    MK_64(0x9716D35D,0xD4917C38),
+    MK_64(0xE780DF12,0x6FD31D3A),
+    MK_64(0x797846B6,0xC898303A),
+    MK_64(0xB172C2A8,0xB3572A3B),
+    MK_64(0xC9BC8203,0xA6104A6C),
+    MK_64(0x65909338,0xD75624F4),
+    MK_64(0x94BCC568,0x4B3F81A0),
+    MK_64(0x3EBBF51E,0x10ECFD46),
+    MK_64(0x2DF50F0B,0xEEB08542),
+    MK_64(0x3B5A6530,0x0DBC6516),
+    MK_64(0x484B9CD2,0x167BBCE1),
+    MK_64(0x2D136947,0xD4CBAFEA)
+    };
+
+/* blkSize = 1024 bits. hashSize =  512 bits */
+const u64b_t SKEIN1024_IV_512[] =
+    {
+    MK_64(0xCAEC0E5D,0x7C1B1B18),
+    MK_64(0xA01B0E04,0x5F03E802),
+    MK_64(0x33840451,0xED912885),
+    MK_64(0x374AFB04,0xEAEC2E1C),
+    MK_64(0xDF25A0E2,0x813581F7),
+    MK_64(0xE4004093,0x8B12F9D2),
+    MK_64(0xA662D539,0xC2ED39B6),
+    MK_64(0xFA8B85CF,0x45D8C75A),
+    MK_64(0x8316ED8E,0x29EDE796),
+    MK_64(0x053289C0,0x2E9F91B8),
+    MK_64(0xC3F8EF1D,0x6D518B73),
+    MK_64(0xBDCEC3C4,0xD5EF332E),
+    MK_64(0x549A7E52,0x22974487),
+    MK_64(0x67070872,0x5B749816),
+    MK_64(0xB9CD28FB,0xF0581BD1),
+    MK_64(0x0E2940B8,0x15804974)
+    };
+
+/* blkSize = 1024 bits. hashSize = 1024 bits */
+const u64b_t SKEIN1024_IV_1024[] =
+    {
+    MK_64(0xD593DA07,0x41E72355),
+    MK_64(0x15B5E511,0xAC73E00C),
+    MK_64(0x5180E5AE,0xBAF2C4F0),
+    MK_64(0x03BD41D3,0xFCBCAFAF),
+    MK_64(0x1CAEC6FD,0x1983A898),
+    MK_64(0x6E510B8B,0xCDD0589F),
+    MK_64(0x77E2BDFD,0xC6394ADA),
+    MK_64(0xC11E1DB5,0x24DCB0A3),
+    MK_64(0xD6D14AF9,0xC6329AB5),
+    MK_64(0x6A9B0BFC,0x6EB67E0D),
+    MK_64(0x9243C60D,0xCCFF1332),
+    MK_64(0x1A1F1DDE,0x743F02D4),
+    MK_64(0x0996753C,0x10ED0BB8),
+    MK_64(0x6572DD22,0xF2B4969A),
+    MK_64(0x61FD3062,0xD00A579A),
+    MK_64(0x1DE0536E,0x8682E539)
+    };
+
+
+#ifndef SKEIN_USE_ASM
+#define SKEIN_USE_ASM   (0)                     /* default is all C code (no ASM) */
+#endif
+
+#ifndef SKEIN_LOOP
+#define SKEIN_LOOP 001                          /* default: unroll 256 and 512, but not 1024 */
+#endif
+
+#define BLK_BITS        (WCNT*64)               /* some useful definitions for code here */
+#define KW_TWK_BASE     (0)
+#define KW_KEY_BASE     (3)
+#define ks              (kw + KW_KEY_BASE)                
+#define ts              (kw + KW_TWK_BASE)
+
+#ifdef SKEIN_DEBUG
+#define DebugSaveTweak(ctx) { ctx->h.T[0] = ts[0]; ctx->h.T[1] = ts[1]; }
+#else
+#define DebugSaveTweak(ctx)
+#endif
+
+/*****************************  Skein_256 ******************************/
+#if !(SKEIN_USE_ASM & 256)
+static void Skein_256_Process_Block(Skein_256_Ctxt_t *ctx,const u08b_t *blkPtr,size_t blkCnt,size_t byteCntAdd)
+    { /* do it in C */
+    enum
+        {
+        WCNT = SKEIN_256_STATE_WORDS
+        };
+#undef  RCNT
+#define RCNT  (SKEIN_256_ROUNDS_TOTAL/8)
+
+#ifdef  SKEIN_LOOP                              /* configure how much to unroll the loop */
+#define SKEIN_UNROLL_256 (((SKEIN_LOOP)/100)%10)
+#else
+#define SKEIN_UNROLL_256 (0)
+#endif
+
+#if SKEIN_UNROLL_256
+#if (RCNT % SKEIN_UNROLL_256)
+#error "Invalid SKEIN_UNROLL_256"               /* sanity check on unroll count */
+#endif
+    size_t  r;
+    u64b_t  kw[WCNT+4+RCNT*2];                  /* key schedule words : chaining vars + tweak + "rotation"*/
+#else
+    u64b_t  kw[WCNT+4];                         /* key schedule words : chaining vars + tweak */
+#endif
+    u64b_t  X0,X1,X2,X3;                        /* local copy of context vars, for speed */
+    u64b_t  w [WCNT];                           /* local copy of input block */
+#ifdef SKEIN_DEBUG
+    const u64b_t *Xptr[4];                      /* use for debugging (help compiler put Xn in registers) */
+    Xptr[0] = &X0;  Xptr[1] = &X1;  Xptr[2] = &X2;  Xptr[3] = &X3;
+#endif
+    Skein_assert(blkCnt != 0);                  /* never call with blkCnt == 0! */
+    ts[0] = ctx->h.T[0];
+    ts[1] = ctx->h.T[1];
+    do  {
+        /* this implementation only supports 2**64 input bytes (no carry out here) */
+        ts[0] += byteCntAdd;                    /* update processed length */
+
+        /* precompute the key schedule for this block */
+        ks[0] = ctx->X[0];     
+        ks[1] = ctx->X[1];
+        ks[2] = ctx->X[2];
+        ks[3] = ctx->X[3];
+        ks[4] = ks[0] ^ ks[1] ^ ks[2] ^ ks[3] ^ SKEIN_KS_PARITY;
+
+        ts[2] = ts[0] ^ ts[1];
+
+        Skein_Get64_LSB_First(w,blkPtr,WCNT);   /* get input block in little-endian format */
+        DebugSaveTweak(ctx);
+        Skein_Show_Block(BLK_BITS,&ctx->h,ctx->X,blkPtr,w,ks,ts);
+
+        X0 = w[0] + ks[0];                      /* do the first full key injection */
+        X1 = w[1] + ks[1] + ts[0];
+        X2 = w[2] + ks[2] + ts[1];
+        X3 = w[3] + ks[3];
+
+        Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INITIAL,Xptr);    /* show starting state values */
+
+        blkPtr += SKEIN_256_BLOCK_BYTES;
+
+        /* run the rounds */
+
+#define Round256(p0,p1,p2,p3,ROT,rNum)                              \
+    X##p0 += X##p1; X##p1 = RotL_64(X##p1,ROT##_0); X##p1 ^= X##p0; \
+    X##p2 += X##p3; X##p3 = RotL_64(X##p3,ROT##_1); X##p3 ^= X##p2; \
+
+#if SKEIN_UNROLL_256 == 0                       
+#define R256(p0,p1,p2,p3,ROT,rNum)           /* fully unrolled */   \
+    Round256(p0,p1,p2,p3,ROT,rNum)                                  \
+    Skein_Show_R_Ptr(BLK_BITS,&ctx->h,rNum,Xptr);
+
+#define I256(R)                                                     \
+    X0   += ks[((R)+1) % 5];    /* inject the key schedule value */ \
+    X1   += ks[((R)+2) % 5] + ts[((R)+1) % 3];                      \
+    X2   += ks[((R)+3) % 5] + ts[((R)+2) % 3];                      \
+    X3   += ks[((R)+4) % 5] +     (R)+1;                            \
+    Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INJECT,Xptr);
+#else                                       /* looping version */
+#define R256(p0,p1,p2,p3,ROT,rNum)                                  \
+    Round256(p0,p1,p2,p3,ROT,rNum)                                  \
+    Skein_Show_R_Ptr(BLK_BITS,&ctx->h,4*(r-1)+rNum,Xptr);
+
+#define I256(R)                                                     \
+    X0   += ks[r+(R)+0];        /* inject the key schedule value */ \
+    X1   += ks[r+(R)+1] + ts[r+(R)+0];                              \
+    X2   += ks[r+(R)+2] + ts[r+(R)+1];                              \
+    X3   += ks[r+(R)+3] +    r+(R)   ;                              \
+    ks[r + (R)+4    ]   = ks[r+(R)-1];     /* rotate key schedule */\
+    ts[r + (R)+2    ]   = ts[r+(R)-1];                              \
+    Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INJECT,Xptr);
+
+    for (r=1;r < 2*RCNT;r+=2*SKEIN_UNROLL_256)  /* loop thru it */
+#endif  
+        {    
+#define R256_8_rounds(R)                  \
+        R256(0,1,2,3,R_256_0,8*(R) + 1);  \
+        R256(0,3,2,1,R_256_1,8*(R) + 2);  \
+        R256(0,1,2,3,R_256_2,8*(R) + 3);  \
+        R256(0,3,2,1,R_256_3,8*(R) + 4);  \
+        I256(2*(R));                      \
+        R256(0,1,2,3,R_256_4,8*(R) + 5);  \
+        R256(0,3,2,1,R_256_5,8*(R) + 6);  \
+        R256(0,1,2,3,R_256_6,8*(R) + 7);  \
+        R256(0,3,2,1,R_256_7,8*(R) + 8);  \
+        I256(2*(R)+1);
+
+        R256_8_rounds( 0);
+
+#define R256_Unroll_R(NN) ((SKEIN_UNROLL_256 == 0 && SKEIN_256_ROUNDS_TOTAL/8 > (NN)) || (SKEIN_UNROLL_256 > (NN)))
+
+  #if   R256_Unroll_R( 1)
+        R256_8_rounds( 1);
+  #endif
+  #if   R256_Unroll_R( 2)
+        R256_8_rounds( 2);
+  #endif
+  #if   R256_Unroll_R( 3)
+        R256_8_rounds( 3);
+  #endif
+  #if   R256_Unroll_R( 4)
+        R256_8_rounds( 4);
+  #endif
+  #if   R256_Unroll_R( 5)
+        R256_8_rounds( 5);
+  #endif
+  #if   R256_Unroll_R( 6)
+        R256_8_rounds( 6);
+  #endif
+  #if   R256_Unroll_R( 7)
+        R256_8_rounds( 7);
+  #endif
+  #if   R256_Unroll_R( 8)
+        R256_8_rounds( 8);
+  #endif
+  #if   R256_Unroll_R( 9)
+        R256_8_rounds( 9);
+  #endif
+  #if   R256_Unroll_R(10)
+        R256_8_rounds(10);
+  #endif
+  #if   R256_Unroll_R(11)
+        R256_8_rounds(11);
+  #endif
+  #if   R256_Unroll_R(12)
+        R256_8_rounds(12);
+  #endif
+  #if   R256_Unroll_R(13)
+        R256_8_rounds(13);
+  #endif
+  #if   R256_Unroll_R(14)
+        R256_8_rounds(14);
+  #endif
+  #if  (SKEIN_UNROLL_256 > 14)
+#error  "need more unrolling in Skein_256_Process_Block"
+  #endif
+        }
+        /* do the final "feedforward" xor, update context chaining vars */
+        ctx->X[0] = X0 ^ w[0];
+        ctx->X[1] = X1 ^ w[1];
+        ctx->X[2] = X2 ^ w[2];
+        ctx->X[3] = X3 ^ w[3];
+
+        Skein_Show_Round(BLK_BITS,&ctx->h,SKEIN_RND_FEED_FWD,ctx->X);
+
+        ts[1] &= ~SKEIN_T1_FLAG_FIRST;
+        }
+    while (--blkCnt);
+    ctx->h.T[0] = ts[0];
+    ctx->h.T[1] = ts[1];
+    }
+
+#if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF)
+static size_t Skein_256_Process_Block_CodeSize(void)
+    {
+    return ((u08b_t *) Skein_256_Process_Block_CodeSize) -
+           ((u08b_t *) Skein_256_Process_Block);
+    }
+static uint_t Skein_256_Unroll_Cnt(void)
+    {
+    return SKEIN_UNROLL_256;
+    }
+#endif
+#endif
+
+/*****************************  Skein_512 ******************************/
+#if !(SKEIN_USE_ASM & 512)
+static void Skein_512_Process_Block(Skein_512_Ctxt_t *ctx,const u08b_t *blkPtr,size_t blkCnt,size_t byteCntAdd)
+    { /* do it in C */
+    enum
+        {
+        WCNT = SKEIN_512_STATE_WORDS
+        };
+#undef  RCNT
+#define RCNT  (SKEIN_512_ROUNDS_TOTAL/8)
+
+#ifdef  SKEIN_LOOP                              /* configure how much to unroll the loop */
+#define SKEIN_UNROLL_512 (((SKEIN_LOOP)/10)%10)
+#else
+#define SKEIN_UNROLL_512 (0)
+#endif
+
+#if SKEIN_UNROLL_512
+#if (RCNT % SKEIN_UNROLL_512)
+#error "Invalid SKEIN_UNROLL_512"               /* sanity check on unroll count */
+#endif
+    size_t  r;
+    u64b_t  kw[WCNT+4+RCNT*2];                  /* key schedule words : chaining vars + tweak + "rotation"*/
+#else
+    u64b_t  kw[WCNT+4];                         /* key schedule words : chaining vars + tweak */
+#endif
+    u64b_t  X0,X1,X2,X3,X4,X5,X6,X7;            /* local copy of vars, for speed */
+    u64b_t  w [WCNT];                           /* local copy of input block */
+#ifdef SKEIN_DEBUG
+    const u64b_t *Xptr[8];                      /* use for debugging (help compiler put Xn in registers) */
+    Xptr[0] = &X0;  Xptr[1] = &X1;  Xptr[2] = &X2;  Xptr[3] = &X3;
+    Xptr[4] = &X4;  Xptr[5] = &X5;  Xptr[6] = &X6;  Xptr[7] = &X7;
+#endif
+
+    Skein_assert(blkCnt != 0);                  /* never call with blkCnt == 0! */
+    ts[0] = ctx->h.T[0];
+    ts[1] = ctx->h.T[1];
+    do  {
+        /* this implementation only supports 2**64 input bytes (no carry out here) */
+        ts[0] += byteCntAdd;                    /* update processed length */
+
+        /* precompute the key schedule for this block */
+        ks[0] = ctx->X[0];
+        ks[1] = ctx->X[1];
+        ks[2] = ctx->X[2];
+        ks[3] = ctx->X[3];
+        ks[4] = ctx->X[4];
+        ks[5] = ctx->X[5];
+        ks[6] = ctx->X[6];
+        ks[7] = ctx->X[7];
+        ks[8] = ks[0] ^ ks[1] ^ ks[2] ^ ks[3] ^ 
+                ks[4] ^ ks[5] ^ ks[6] ^ ks[7] ^ SKEIN_KS_PARITY;
+
+        ts[2] = ts[0] ^ ts[1];
+
+        Skein_Get64_LSB_First(w,blkPtr,WCNT); /* get input block in little-endian format */
+        DebugSaveTweak(ctx);
+        Skein_Show_Block(BLK_BITS,&ctx->h,ctx->X,blkPtr,w,ks,ts);
+
+        X0   = w[0] + ks[0];                    /* do the first full key injection */
+        X1   = w[1] + ks[1];
+        X2   = w[2] + ks[2];
+        X3   = w[3] + ks[3];
+        X4   = w[4] + ks[4];
+        X5   = w[5] + ks[5] + ts[0];
+        X6   = w[6] + ks[6] + ts[1];
+        X7   = w[7] + ks[7];
+
+        blkPtr += SKEIN_512_BLOCK_BYTES;
+
+        Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INITIAL,Xptr);
+        /* run the rounds */
+#define Round512(p0,p1,p2,p3,p4,p5,p6,p7,ROT,rNum)                  \
+    X##p0 += X##p1; X##p1 = RotL_64(X##p1,ROT##_0); X##p1 ^= X##p0; \
+    X##p2 += X##p3; X##p3 = RotL_64(X##p3,ROT##_1); X##p3 ^= X##p2; \
+    X##p4 += X##p5; X##p5 = RotL_64(X##p5,ROT##_2); X##p5 ^= X##p4; \
+    X##p6 += X##p7; X##p7 = RotL_64(X##p7,ROT##_3); X##p7 ^= X##p6; \
+
+#if SKEIN_UNROLL_512 == 0                       
+#define R512(p0,p1,p2,p3,p4,p5,p6,p7,ROT,rNum)      /* unrolled */  \
+    Round512(p0,p1,p2,p3,p4,p5,p6,p7,ROT,rNum)                      \
+    Skein_Show_R_Ptr(BLK_BITS,&ctx->h,rNum,Xptr);
+
+#define I512(R)                                                     \
+    X0   += ks[((R)+1) % 9];   /* inject the key schedule value */  \
+    X1   += ks[((R)+2) % 9];                                        \
+    X2   += ks[((R)+3) % 9];                                        \
+    X3   += ks[((R)+4) % 9];                                        \
+    X4   += ks[((R)+5) % 9];                                        \
+    X5   += ks[((R)+6) % 9] + ts[((R)+1) % 3];                      \
+    X6   += ks[((R)+7) % 9] + ts[((R)+2) % 3];                      \
+    X7   += ks[((R)+8) % 9] +     (R)+1;                            \
+    Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INJECT,Xptr);
+#else                                       /* looping version */
+#define R512(p0,p1,p2,p3,p4,p5,p6,p7,ROT,rNum)                      \
+    Round512(p0,p1,p2,p3,p4,p5,p6,p7,ROT,rNum)                      \
+    Skein_Show_R_Ptr(BLK_BITS,&ctx->h,4*(r-1)+rNum,Xptr);
+
+#define I512(R)                                                     \
+    X0   += ks[r+(R)+0];        /* inject the key schedule value */ \
+    X1   += ks[r+(R)+1];                                            \
+    X2   += ks[r+(R)+2];                                            \
+    X3   += ks[r+(R)+3];                                            \
+    X4   += ks[r+(R)+4];                                            \
+    X5   += ks[r+(R)+5] + ts[r+(R)+0];                              \
+    X6   += ks[r+(R)+6] + ts[r+(R)+1];                              \
+    X7   += ks[r+(R)+7] +    r+(R)   ;                              \
+    ks[r +       (R)+8] = ks[r+(R)-1];  /* rotate key schedule */   \
+    ts[r +       (R)+2] = ts[r+(R)-1];                              \
+    Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INJECT,Xptr);
+
+    for (r=1;r < 2*RCNT;r+=2*SKEIN_UNROLL_512)   /* loop thru it */
+#endif                         /* end of looped code definitions */
+        {
+#define R512_8_rounds(R)  /* do 8 full rounds */  \
+        R512(0,1,2,3,4,5,6,7,R_512_0,8*(R)+ 1);   \
+        R512(2,1,4,7,6,5,0,3,R_512_1,8*(R)+ 2);   \
+        R512(4,1,6,3,0,5,2,7,R_512_2,8*(R)+ 3);   \
+        R512(6,1,0,7,2,5,4,3,R_512_3,8*(R)+ 4);   \
+        I512(2*(R));                              \
+        R512(0,1,2,3,4,5,6,7,R_512_4,8*(R)+ 5);   \
+        R512(2,1,4,7,6,5,0,3,R_512_5,8*(R)+ 6);   \
+        R512(4,1,6,3,0,5,2,7,R_512_6,8*(R)+ 7);   \
+        R512(6,1,0,7,2,5,4,3,R_512_7,8*(R)+ 8);   \
+        I512(2*(R)+1);        /* and key injection */
+
+        R512_8_rounds( 0);
+
+#define R512_Unroll_R(NN) ((SKEIN_UNROLL_512 == 0 && SKEIN_512_ROUNDS_TOTAL/8 > (NN)) || (SKEIN_UNROLL_512 > (NN)))
+
+  #if   R512_Unroll_R( 1)
+        R512_8_rounds( 1);
+  #endif
+  #if   R512_Unroll_R( 2)
+        R512_8_rounds( 2);
+  #endif
+  #if   R512_Unroll_R( 3)
+        R512_8_rounds( 3);
+  #endif
+  #if   R512_Unroll_R( 4)
+        R512_8_rounds( 4);
+  #endif
+  #if   R512_Unroll_R( 5)
+        R512_8_rounds( 5);
+  #endif
+  #if   R512_Unroll_R( 6)
+        R512_8_rounds( 6);
+  #endif
+  #if   R512_Unroll_R( 7)
+        R512_8_rounds( 7);
+  #endif
+  #if   R512_Unroll_R( 8)
+        R512_8_rounds( 8);
+  #endif
+  #if   R512_Unroll_R( 9)
+        R512_8_rounds( 9);
+  #endif
+  #if   R512_Unroll_R(10)
+        R512_8_rounds(10);
+  #endif
+  #if   R512_Unroll_R(11)
+        R512_8_rounds(11);
+  #endif
+  #if   R512_Unroll_R(12)
+        R512_8_rounds(12);
+  #endif
+  #if   R512_Unroll_R(13)
+        R512_8_rounds(13);
+  #endif
+  #if   R512_Unroll_R(14)
+        R512_8_rounds(14);
+  #endif
+  #if  (SKEIN_UNROLL_512 > 14)
+#error  "need more unrolling in Skein_512_Process_Block"
+  #endif
+        }
+
+        /* do the final "feedforward" xor, update context chaining vars */
+        ctx->X[0] = X0 ^ w[0];
+        ctx->X[1] = X1 ^ w[1];
+        ctx->X[2] = X2 ^ w[2];
+        ctx->X[3] = X3 ^ w[3];
+        ctx->X[4] = X4 ^ w[4];
+        ctx->X[5] = X5 ^ w[5];
+        ctx->X[6] = X6 ^ w[6];
+        ctx->X[7] = X7 ^ w[7];
+        Skein_Show_Round(BLK_BITS,&ctx->h,SKEIN_RND_FEED_FWD,ctx->X);
+
+        ts[1] &= ~SKEIN_T1_FLAG_FIRST;
+        }
+    while (--blkCnt);
+    ctx->h.T[0] = ts[0];
+    ctx->h.T[1] = ts[1];
+    }
+
+#if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF)
+static size_t Skein_512_Process_Block_CodeSize(void)
+    {
+    return ((u08b_t *) Skein_512_Process_Block_CodeSize) -
+           ((u08b_t *) Skein_512_Process_Block);
+    }
+static uint_t Skein_512_Unroll_Cnt(void)
+    {
+    return SKEIN_UNROLL_512;
+    }
+#endif
+#endif
+
+/*****************************  Skein1024 ******************************/
+#if !(SKEIN_USE_ASM & 1024)
+static void Skein1024_Process_Block(Skein1024_Ctxt_t *ctx,const u08b_t *blkPtr,size_t blkCnt,size_t byteCntAdd)
+    { /* do it in C, always looping (unrolled is bigger AND slower!) */
+    enum
+        {
+        WCNT = SKEIN1024_STATE_WORDS
+        };
+#undef  RCNT
+#define RCNT  (SKEIN1024_ROUNDS_TOTAL/8)
+
+#ifdef  SKEIN_LOOP                              /* configure how much to unroll the loop */
+#define SKEIN_UNROLL_1024 ((SKEIN_LOOP)%10)
+#else
+#define SKEIN_UNROLL_1024 (0)
+#endif
+
+#if (SKEIN_UNROLL_1024 != 0)
+#if (RCNT % SKEIN_UNROLL_1024)
+#error "Invalid SKEIN_UNROLL_1024"              /* sanity check on unroll count */
+#endif
+    size_t  r;
+    u64b_t  kw[WCNT+4+RCNT*2];                  /* key schedule words : chaining vars + tweak + "rotation"*/
+#else
+    u64b_t  kw[WCNT+4];                         /* key schedule words : chaining vars + tweak */
+#endif
+
+    u64b_t  X00,X01,X02,X03,X04,X05,X06,X07,    /* local copy of vars, for speed */
+            X08,X09,X10,X11,X12,X13,X14,X15;
+    u64b_t  w [WCNT];                           /* local copy of input block */
+#ifdef SKEIN_DEBUG
+    const u64b_t *Xptr[16];                     /* use for debugging (help compiler put Xn in registers) */
+    Xptr[ 0] = &X00;  Xptr[ 1] = &X01;  Xptr[ 2] = &X02;  Xptr[ 3] = &X03;
+    Xptr[ 4] = &X04;  Xptr[ 5] = &X05;  Xptr[ 6] = &X06;  Xptr[ 7] = &X07;
+    Xptr[ 8] = &X08;  Xptr[ 9] = &X09;  Xptr[10] = &X10;  Xptr[11] = &X11;
+    Xptr[12] = &X12;  Xptr[13] = &X13;  Xptr[14] = &X14;  Xptr[15] = &X15;
+#endif
+
+    Skein_assert(blkCnt != 0);                  /* never call with blkCnt == 0! */
+    ts[0] = ctx->h.T[0];
+    ts[1] = ctx->h.T[1];
+    do  {
+        /* this implementation only supports 2**64 input bytes (no carry out here) */
+        ts[0] += byteCntAdd;                    /* update processed length */
+
+        /* precompute the key schedule for this block */
+        ks[ 0] = ctx->X[ 0];
+        ks[ 1] = ctx->X[ 1];
+        ks[ 2] = ctx->X[ 2];
+        ks[ 3] = ctx->X[ 3];
+        ks[ 4] = ctx->X[ 4];
+        ks[ 5] = ctx->X[ 5];
+        ks[ 6] = ctx->X[ 6];
+        ks[ 7] = ctx->X[ 7];
+        ks[ 8] = ctx->X[ 8];
+        ks[ 9] = ctx->X[ 9];
+        ks[10] = ctx->X[10];
+        ks[11] = ctx->X[11];
+        ks[12] = ctx->X[12];
+        ks[13] = ctx->X[13];
+        ks[14] = ctx->X[14];
+        ks[15] = ctx->X[15];
+        ks[16] = ks[ 0] ^ ks[ 1] ^ ks[ 2] ^ ks[ 3] ^
+                 ks[ 4] ^ ks[ 5] ^ ks[ 6] ^ ks[ 7] ^
+                 ks[ 8] ^ ks[ 9] ^ ks[10] ^ ks[11] ^
+                 ks[12] ^ ks[13] ^ ks[14] ^ ks[15] ^ SKEIN_KS_PARITY;
+
+        ts[2]  = ts[0] ^ ts[1];
+
+        Skein_Get64_LSB_First(w,blkPtr,WCNT); /* get input block in little-endian format */
+        DebugSaveTweak(ctx);
+        Skein_Show_Block(BLK_BITS,&ctx->h,ctx->X,blkPtr,w,ks,ts);
+
+        X00    = w[ 0] + ks[ 0];                 /* do the first full key injection */
+        X01    = w[ 1] + ks[ 1];
+        X02    = w[ 2] + ks[ 2];
+        X03    = w[ 3] + ks[ 3];
+        X04    = w[ 4] + ks[ 4];
+        X05    = w[ 5] + ks[ 5];
+        X06    = w[ 6] + ks[ 6];
+        X07    = w[ 7] + ks[ 7];
+        X08    = w[ 8] + ks[ 8];
+        X09    = w[ 9] + ks[ 9];
+        X10    = w[10] + ks[10];
+        X11    = w[11] + ks[11];
+        X12    = w[12] + ks[12];
+        X13    = w[13] + ks[13] + ts[0];
+        X14    = w[14] + ks[14] + ts[1];
+        X15    = w[15] + ks[15];
+
+        Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INITIAL,Xptr);
+
+#define Round1024(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,pA,pB,pC,pD,pE,pF,ROT,rNum) \
+    X##p0 += X##p1; X##p1 = RotL_64(X##p1,ROT##_0); X##p1 ^= X##p0;   \
+    X##p2 += X##p3; X##p3 = RotL_64(X##p3,ROT##_1); X##p3 ^= X##p2;   \
+    X##p4 += X##p5; X##p5 = RotL_64(X##p5,ROT##_2); X##p5 ^= X##p4;   \
+    X##p6 += X##p7; X##p7 = RotL_64(X##p7,ROT##_3); X##p7 ^= X##p6;   \
+    X##p8 += X##p9; X##p9 = RotL_64(X##p9,ROT##_4); X##p9 ^= X##p8;   \
+    X##pA += X##pB; X##pB = RotL_64(X##pB,ROT##_5); X##pB ^= X##pA;   \
+    X##pC += X##pD; X##pD = RotL_64(X##pD,ROT##_6); X##pD ^= X##pC;   \
+    X##pE += X##pF; X##pF = RotL_64(X##pF,ROT##_7); X##pF ^= X##pE;   \
+
+#if SKEIN_UNROLL_1024 == 0                      
+#define R1024(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,pA,pB,pC,pD,pE,pF,ROT,rn) \
+    Round1024(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,pA,pB,pC,pD,pE,pF,ROT,rn) \
+    Skein_Show_R_Ptr(BLK_BITS,&ctx->h,rn,Xptr);
+
+#define I1024(R)                                                      \
+    X00   += ks[((R)+ 1) % 17]; /* inject the key schedule value */   \
+    X01   += ks[((R)+ 2) % 17];                                       \
+    X02   += ks[((R)+ 3) % 17];                                       \
+    X03   += ks[((R)+ 4) % 17];                                       \
+    X04   += ks[((R)+ 5) % 17];                                       \
+    X05   += ks[((R)+ 6) % 17];                                       \
+    X06   += ks[((R)+ 7) % 17];                                       \
+    X07   += ks[((R)+ 8) % 17];                                       \
+    X08   += ks[((R)+ 9) % 17];                                       \
+    X09   += ks[((R)+10) % 17];                                       \
+    X10   += ks[((R)+11) % 17];                                       \
+    X11   += ks[((R)+12) % 17];                                       \
+    X12   += ks[((R)+13) % 17];                                       \
+    X13   += ks[((R)+14) % 17] + ts[((R)+1) % 3];                     \
+    X14   += ks[((R)+15) % 17] + ts[((R)+2) % 3];                     \
+    X15   += ks[((R)+16) % 17] +     (R)+1;                           \
+    Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INJECT,Xptr); 
+#else                                       /* looping version */
+#define R1024(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,pA,pB,pC,pD,pE,pF,ROT,rn) \
+    Round1024(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,pA,pB,pC,pD,pE,pF,ROT,rn) \
+    Skein_Show_R_Ptr(BLK_BITS,&ctx->h,4*(r-1)+rn,Xptr);
+
+#define I1024(R)                                                      \
+    X00   += ks[r+(R)+ 0];    /* inject the key schedule value */     \
+    X01   += ks[r+(R)+ 1];                                            \
+    X02   += ks[r+(R)+ 2];                                            \
+    X03   += ks[r+(R)+ 3];                                            \
+    X04   += ks[r+(R)+ 4];                                            \
+    X05   += ks[r+(R)+ 5];                                            \
+    X06   += ks[r+(R)+ 6];                                            \
+    X07   += ks[r+(R)+ 7];                                            \
+    X08   += ks[r+(R)+ 8];                                            \
+    X09   += ks[r+(R)+ 9];                                            \
+    X10   += ks[r+(R)+10];                                            \
+    X11   += ks[r+(R)+11];                                            \
+    X12   += ks[r+(R)+12];                                            \
+    X13   += ks[r+(R)+13] + ts[r+(R)+0];                              \
+    X14   += ks[r+(R)+14] + ts[r+(R)+1];                              \
+    X15   += ks[r+(R)+15] +    r+(R)   ;                              \
+    ks[r  +       (R)+16] = ks[r+(R)-1];  /* rotate key schedule */   \
+    ts[r  +       (R)+ 2] = ts[r+(R)-1];                              \
+    Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INJECT,Xptr);
+
+    for (r=1;r <= 2*RCNT;r+=2*SKEIN_UNROLL_1024)    /* loop thru it */
+#endif  
+        {
+#define R1024_8_rounds(R)    /* do 8 full rounds */                               \
+        R1024(00,01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,R1024_0,8*(R) + 1); \
+        R1024(00,09,02,13,06,11,04,15,10,07,12,03,14,05,08,01,R1024_1,8*(R) + 2); \
+        R1024(00,07,02,05,04,03,06,01,12,15,14,13,08,11,10,09,R1024_2,8*(R) + 3); \
+        R1024(00,15,02,11,06,13,04,09,14,01,08,05,10,03,12,07,R1024_3,8*(R) + 4); \
+        I1024(2*(R));                                                             \
+        R1024(00,01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,R1024_4,8*(R) + 5); \
+        R1024(00,09,02,13,06,11,04,15,10,07,12,03,14,05,08,01,R1024_5,8*(R) + 6); \
+        R1024(00,07,02,05,04,03,06,01,12,15,14,13,08,11,10,09,R1024_6,8*(R) + 7); \
+        R1024(00,15,02,11,06,13,04,09,14,01,08,05,10,03,12,07,R1024_7,8*(R) + 8); \
+        I1024(2*(R)+1);
+
+        R1024_8_rounds( 0);
+
+#define R1024_Unroll_R(NN) ((SKEIN_UNROLL_1024 == 0 && SKEIN1024_ROUNDS_TOTAL/8 > (NN)) || (SKEIN_UNROLL_1024 > (NN)))
+
+  #if   R1024_Unroll_R( 1)
+        R1024_8_rounds( 1);
+  #endif
+  #if   R1024_Unroll_R( 2)
+        R1024_8_rounds( 2);
+  #endif
+  #if   R1024_Unroll_R( 3)
+        R1024_8_rounds( 3);
+  #endif
+  #if   R1024_Unroll_R( 4)
+        R1024_8_rounds( 4);
+  #endif
+  #if   R1024_Unroll_R( 5)
+        R1024_8_rounds( 5);
+  #endif
+  #if   R1024_Unroll_R( 6)
+        R1024_8_rounds( 6);
+  #endif
+  #if   R1024_Unroll_R( 7)
+        R1024_8_rounds( 7);
+  #endif
+  #if   R1024_Unroll_R( 8)
+        R1024_8_rounds( 8);
+  #endif
+  #if   R1024_Unroll_R( 9)
+        R1024_8_rounds( 9);
+  #endif
+  #if   R1024_Unroll_R(10)
+        R1024_8_rounds(10);
+  #endif
+  #if   R1024_Unroll_R(11)
+        R1024_8_rounds(11);
+  #endif
+  #if   R1024_Unroll_R(12)
+        R1024_8_rounds(12);
+  #endif
+  #if   R1024_Unroll_R(13)
+        R1024_8_rounds(13);
+  #endif
+  #if   R1024_Unroll_R(14)
+        R1024_8_rounds(14);
+  #endif
+  #if  (SKEIN_UNROLL_1024 > 14)
+#error  "need more unrolling in Skein_1024_Process_Block"
+  #endif
+        }
+        /* do the final "feedforward" xor, update context chaining vars */
+
+        ctx->X[ 0] = X00 ^ w[ 0];
+        ctx->X[ 1] = X01 ^ w[ 1];
+        ctx->X[ 2] = X02 ^ w[ 2];
+        ctx->X[ 3] = X03 ^ w[ 3];
+        ctx->X[ 4] = X04 ^ w[ 4];
+        ctx->X[ 5] = X05 ^ w[ 5];
+        ctx->X[ 6] = X06 ^ w[ 6];
+        ctx->X[ 7] = X07 ^ w[ 7];
+        ctx->X[ 8] = X08 ^ w[ 8];
+        ctx->X[ 9] = X09 ^ w[ 9];
+        ctx->X[10] = X10 ^ w[10];
+        ctx->X[11] = X11 ^ w[11];
+        ctx->X[12] = X12 ^ w[12];
+        ctx->X[13] = X13 ^ w[13];
+        ctx->X[14] = X14 ^ w[14];
+        ctx->X[15] = X15 ^ w[15];
+
+        Skein_Show_Round(BLK_BITS,&ctx->h,SKEIN_RND_FEED_FWD,ctx->X);
+        
+        ts[1] &= ~SKEIN_T1_FLAG_FIRST;
+        blkPtr += SKEIN1024_BLOCK_BYTES;
+        }
+    while (--blkCnt);
+    ctx->h.T[0] = ts[0];
+    ctx->h.T[1] = ts[1];
+    }
+
+#if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF)
+static size_t Skein1024_Process_Block_CodeSize(void)
+    {
+    return ((u08b_t *) Skein1024_Process_Block_CodeSize) -
+           ((u08b_t *) Skein1024_Process_Block);
+    }
+static uint_t Skein1024_Unroll_Cnt(void)
+    {
+    return SKEIN_UNROLL_1024;
+    }
+#endif
+#endif
+
+
+#if 0
+/*****************************************************************/
+/*     256-bit Skein                                             */
+/*****************************************************************/
+
+/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+/* init the context for a straight hashing operation  */
+static int Skein_256_Init(Skein_256_Ctxt_t *ctx, size_t hashBitLen)
+    {
+    union
+        {
+        u08b_t  b[SKEIN_256_STATE_BYTES];
+        u64b_t  w[SKEIN_256_STATE_WORDS];
+        } cfg;                              /* config block */
+        
+    Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN);
+    ctx->h.hashBitLen = hashBitLen;         /* output hash bit count */
+
+    switch (hashBitLen)
+        {             /* use pre-computed values, where available */
+#ifndef SKEIN_NO_PRECOMP
+        case  256: memcpy(ctx->X,SKEIN_256_IV_256,sizeof(ctx->X));  break;
+        case  224: memcpy(ctx->X,SKEIN_256_IV_224,sizeof(ctx->X));  break;
+        case  160: memcpy(ctx->X,SKEIN_256_IV_160,sizeof(ctx->X));  break;
+        case  128: memcpy(ctx->X,SKEIN_256_IV_128,sizeof(ctx->X));  break;
+#endif
+        default:
+            /* here if there is no precomputed IV value available */
+            /* build/process the config block, type == CONFIG (could be precomputed) */
+            Skein_Start_New_Type(ctx,CFG_FINAL);        /* set tweaks: T0=0; T1=CFG | FINAL */
+
+            cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);  /* set the schema, version */
+            cfg.w[1] = Skein_Swap64(hashBitLen);        /* hash result length in bits */
+            cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL);
+            memset(&cfg.w[3],0,sizeof(cfg) - 3*sizeof(cfg.w[0])); /* zero pad config block */
+
+            /* compute the initial chaining values from config block */
+            memset(ctx->X,0,sizeof(ctx->X));            /* zero the chaining variables */
+            Skein_256_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN);
+            break;
+        }
+    /* The chaining vars ctx->X are now initialized for the given hashBitLen. */
+    /* Set up to process the data message portion of the hash (default) */
+    Skein_Start_New_Type(ctx,MSG);              /* T0=0, T1= MSG type */
+
+    return SKEIN_SUCCESS;
+    }
+
+/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+/* init the context for a MAC and/or tree hash operation */
+/* [identical to Skein_256_Init() when keyBytes == 0 && treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL] */
+static int Skein_256_InitExt(Skein_256_Ctxt_t *ctx,size_t hashBitLen,u64b_t treeInfo, const u08b_t *key, size_t keyBytes)
+    {
+    union
+        {
+        u08b_t  b[SKEIN_256_STATE_BYTES];
+        u64b_t  w[SKEIN_256_STATE_WORDS];
+        } cfg;                              /* config block */
+        
+    Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN);
+    Skein_Assert(keyBytes == 0 || key != NULL,SKEIN_FAIL);
+
+    /* compute the initial chaining values ctx->X[], based on key */
+    if (keyBytes == 0)                          /* is there a key? */
+        {                                   
+        memset(ctx->X,0,sizeof(ctx->X));        /* no key: use all zeroes as key for config block */
+        }
+    else                                        /* here to pre-process a key */
+        {
+        Skein_assert(sizeof(cfg.b) >= sizeof(ctx->X));
+        /* do a mini-Init right here */
+        ctx->h.hashBitLen=8*sizeof(ctx->X);     /* set output hash bit count = state size */
+        Skein_Start_New_Type(ctx,KEY);          /* set tweaks: T0 = 0; T1 = KEY type */
+        memset(ctx->X,0,sizeof(ctx->X));        /* zero the initial chaining variables */
+        Skein_256_Update(ctx,key,keyBytes);     /* hash the key */
+        Skein_256_Final_Pad(ctx,cfg.b);         /* put result into cfg.b[] */
+        memcpy(ctx->X,cfg.b,sizeof(cfg.b));     /* copy over into ctx->X[] */
+#if SKEIN_NEED_SWAP
+        {
+        uint_t i;
+        for (i=0;i<SKEIN_256_STATE_WORDS;i++)   /* convert key bytes to context words */
+            ctx->X[i] = Skein_Swap64(ctx->X[i]);
+        }
+#endif
+        }
+    /* build/process the config block, type == CONFIG (could be precomputed for each key) */
+    ctx->h.hashBitLen = hashBitLen;             /* output hash bit count */
+    Skein_Start_New_Type(ctx,CFG_FINAL);
+
+    memset(&cfg.w,0,sizeof(cfg.w));             /* pre-pad cfg.w[] with zeroes */
+    cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);
+    cfg.w[1] = Skein_Swap64(hashBitLen);        /* hash result length in bits */
+    cfg.w[2] = Skein_Swap64(treeInfo);          /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */
+
+    Skein_Show_Key(256,&ctx->h,key,keyBytes);
+
+    /* compute the initial chaining values from config block */
+    Skein_256_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN);
+
+    /* The chaining vars ctx->X are now initialized */
+    /* Set up to process the data message portion of the hash (default) */
+    ctx->h.bCnt = 0;                            /* buffer b[] starts out empty */
+    Skein_Start_New_Type(ctx,MSG);
+    
+    return SKEIN_SUCCESS;
+    }
+#endif
+
+/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+/* process the input bytes */
+static int Skein_256_Update(Skein_256_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt)
+    {
+    size_t n;
+
+    Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES,SKEIN_FAIL);    /* catch uninitialized context */
+
+    /* process full blocks, if any */
+    if (msgByteCnt + ctx->h.bCnt > SKEIN_256_BLOCK_BYTES)
+        {
+        if (ctx->h.bCnt)                              /* finish up any buffered message data */
+            {
+            n = SKEIN_256_BLOCK_BYTES - ctx->h.bCnt;  /* # bytes free in buffer b[] */
+            if (n)
+                {
+                Skein_assert(n < msgByteCnt);         /* check on our logic here */
+                memcpy(&ctx->b[ctx->h.bCnt],msg,n);
+                msgByteCnt  -= n;
+                msg         += n;
+                ctx->h.bCnt += n;
+                }
+            Skein_assert(ctx->h.bCnt == SKEIN_256_BLOCK_BYTES);
+            Skein_256_Process_Block(ctx,ctx->b,1,SKEIN_256_BLOCK_BYTES);
+            ctx->h.bCnt = 0;
+            }
+        /* now process any remaining full blocks, directly from input message data */
+        if (msgByteCnt > SKEIN_256_BLOCK_BYTES)
+            {
+            n = (msgByteCnt-1) / SKEIN_256_BLOCK_BYTES;   /* number of full blocks to process */
+            Skein_256_Process_Block(ctx,msg,n,SKEIN_256_BLOCK_BYTES);
+            msgByteCnt -= n * SKEIN_256_BLOCK_BYTES;
+            msg        += n * SKEIN_256_BLOCK_BYTES;
+            }
+        Skein_assert(ctx->h.bCnt == 0);
+        }
+
+    /* copy any remaining source message data bytes into b[] */
+    if (msgByteCnt)
+        {
+        Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES);
+        memcpy(&ctx->b[ctx->h.bCnt],msg,msgByteCnt);
+        ctx->h.bCnt += msgByteCnt;
+        }
+
+    return SKEIN_SUCCESS;
+    }
+   
+/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+/* finalize the hash computation and output the result */
+static int Skein_256_Final(Skein_256_Ctxt_t *ctx, u08b_t *hashVal)
+    {
+    size_t i,n,byteCnt;
+    u64b_t X[SKEIN_256_STATE_WORDS];
+    Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES,SKEIN_FAIL);    /* catch uninitialized context */
+
+    ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL;                 /* tag as the final block */
+    if (ctx->h.bCnt < SKEIN_256_BLOCK_BYTES)            /* zero pad b[] if necessary */
+        memset(&ctx->b[ctx->h.bCnt],0,SKEIN_256_BLOCK_BYTES - ctx->h.bCnt);
+
+    Skein_256_Process_Block(ctx,ctx->b,1,ctx->h.bCnt);  /* process the final block */
+    
+    /* now output the result */
+    byteCnt = (ctx->h.hashBitLen + 7) >> 3;             /* total number of output bytes */
+
+    /* run Threefish in "counter mode" to generate output */
+    memset(ctx->b,0,sizeof(ctx->b));  /* zero out b[], so it can hold the counter */
+    memcpy(X,ctx->X,sizeof(X));       /* keep a local copy of counter mode "key" */
+    for (i=0;i*SKEIN_256_BLOCK_BYTES < byteCnt;i++)
+        {
+        ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */
+        Skein_Start_New_Type(ctx,OUT_FINAL);
+        Skein_256_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */
+        n = byteCnt - i*SKEIN_256_BLOCK_BYTES;   /* number of output bytes left to go */
+        if (n >= SKEIN_256_BLOCK_BYTES)
+            n  = SKEIN_256_BLOCK_BYTES;
+        Skein_Put64_LSB_First(hashVal+i*SKEIN_256_BLOCK_BYTES,ctx->X,n);   /* "output" the ctr mode bytes */
+        Skein_Show_Final(256,&ctx->h,n,hashVal+i*SKEIN_256_BLOCK_BYTES);
+        memcpy(ctx->X,X,sizeof(X));   /* restore the counter mode key for next time */
+        }
+    return SKEIN_SUCCESS;
+    }
+
+#if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF)
+static size_t Skein_256_API_CodeSize(void)
+    {
+    return ((u08b_t *) Skein_256_API_CodeSize) -
+           ((u08b_t *) Skein_256_Init);
+    }
+#endif
+
+/*****************************************************************/
+/*     512-bit Skein                                             */
+/*****************************************************************/
+
+/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+/* init the context for a straight hashing operation  */
+static int Skein_512_Init(Skein_512_Ctxt_t *ctx, size_t hashBitLen)
+    {
+    union
+        {
+        u08b_t  b[SKEIN_512_STATE_BYTES];
+        u64b_t  w[SKEIN_512_STATE_WORDS];
+        } cfg;                              /* config block */
+        
+    Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN);
+    ctx->h.hashBitLen = hashBitLen;         /* output hash bit count */
+
+    switch (hashBitLen)
+        {             /* use pre-computed values, where available */
+#ifndef SKEIN_NO_PRECOMP
+        case  512: memcpy(ctx->X,SKEIN_512_IV_512,sizeof(ctx->X));  break;
+        case  384: memcpy(ctx->X,SKEIN_512_IV_384,sizeof(ctx->X));  break;
+        case  256: memcpy(ctx->X,SKEIN_512_IV_256,sizeof(ctx->X));  break;
+        case  224: memcpy(ctx->X,SKEIN_512_IV_224,sizeof(ctx->X));  break;
+#endif
+        default:
+            /* here if there is no precomputed IV value available */
+            /* build/process the config block, type == CONFIG (could be precomputed) */
+            Skein_Start_New_Type(ctx,CFG_FINAL);        /* set tweaks: T0=0; T1=CFG | FINAL */
+
+            cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);  /* set the schema, version */
+            cfg.w[1] = Skein_Swap64(hashBitLen);        /* hash result length in bits */
+            cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL);
+            memset(&cfg.w[3],0,sizeof(cfg) - 3*sizeof(cfg.w[0])); /* zero pad config block */
+
+            /* compute the initial chaining values from config block */
+            memset(ctx->X,0,sizeof(ctx->X));            /* zero the chaining variables */
+            Skein_512_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN);
+            break;
+        }
+
+    /* The chaining vars ctx->X are now initialized for the given hashBitLen. */
+    /* Set up to process the data message portion of the hash (default) */
+    Skein_Start_New_Type(ctx,MSG);              /* T0=0, T1= MSG type */
+
+    return SKEIN_SUCCESS;
+    }
+
+#if 0
+/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+/* init the context for a MAC and/or tree hash operation */
+/* [identical to Skein_512_Init() when keyBytes == 0 && treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL] */
+static int Skein_512_InitExt(Skein_512_Ctxt_t *ctx,size_t hashBitLen,u64b_t treeInfo, const u08b_t *key, size_t keyBytes)
+    {
+    union
+        {
+        u08b_t  b[SKEIN_512_STATE_BYTES];
+        u64b_t  w[SKEIN_512_STATE_WORDS];
+        } cfg;                              /* config block */
+        
+    Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN);
+    Skein_Assert(keyBytes == 0 || key != NULL,SKEIN_FAIL);
+
+    /* compute the initial chaining values ctx->X[], based on key */
+    if (keyBytes == 0)                          /* is there a key? */
+        {                                   
+        memset(ctx->X,0,sizeof(ctx->X));        /* no key: use all zeroes as key for config block */
+        }
+    else                                        /* here to pre-process a key */
+        {
+        Skein_assert(sizeof(cfg.b) >= sizeof(ctx->X));
+        /* do a mini-Init right here */
+        ctx->h.hashBitLen=8*sizeof(ctx->X);     /* set output hash bit count = state size */
+        Skein_Start_New_Type(ctx,KEY);          /* set tweaks: T0 = 0; T1 = KEY type */
+        memset(ctx->X,0,sizeof(ctx->X));        /* zero the initial chaining variables */
+        Skein_512_Update(ctx,key,keyBytes);     /* hash the key */
+        Skein_512_Final_Pad(ctx,cfg.b);         /* put result into cfg.b[] */
+        memcpy(ctx->X,cfg.b,sizeof(cfg.b));     /* copy over into ctx->X[] */
+#if SKEIN_NEED_SWAP
+        {
+        uint_t i;
+        for (i=0;i<SKEIN_512_STATE_WORDS;i++)   /* convert key bytes to context words */
+            ctx->X[i] = Skein_Swap64(ctx->X[i]);
+        }
+#endif
+        }
+    /* build/process the config block, type == CONFIG (could be precomputed for each key) */
+    ctx->h.hashBitLen = hashBitLen;             /* output hash bit count */
+    Skein_Start_New_Type(ctx,CFG_FINAL);
+
+    memset(&cfg.w,0,sizeof(cfg.w));             /* pre-pad cfg.w[] with zeroes */
+    cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);
+    cfg.w[1] = Skein_Swap64(hashBitLen);        /* hash result length in bits */
+    cfg.w[2] = Skein_Swap64(treeInfo);          /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */
+
+    Skein_Show_Key(512,&ctx->h,key,keyBytes);
+
+    /* compute the initial chaining values from config block */
+    Skein_512_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN);
+
+    /* The chaining vars ctx->X are now initialized */
+    /* Set up to process the data message portion of the hash (default) */
+    ctx->h.bCnt = 0;                            /* buffer b[] starts out empty */
+    Skein_Start_New_Type(ctx,MSG);
+    
+    return SKEIN_SUCCESS;
+    }
+#endif
+
+/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+/* process the input bytes */
+static int Skein_512_Update(Skein_512_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt)
+    {
+    size_t n;
+
+    Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL);    /* catch uninitialized context */
+
+    /* process full blocks, if any */
+    if (msgByteCnt + ctx->h.bCnt > SKEIN_512_BLOCK_BYTES)
+        {
+        if (ctx->h.bCnt)                              /* finish up any buffered message data */
+            {
+            n = SKEIN_512_BLOCK_BYTES - ctx->h.bCnt;  /* # bytes free in buffer b[] */
+            if (n)
+                {
+                Skein_assert(n < msgByteCnt);         /* check on our logic here */
+                memcpy(&ctx->b[ctx->h.bCnt],msg,n);
+                msgByteCnt  -= n;
+                msg         += n;
+                ctx->h.bCnt += n;
+                }
+            Skein_assert(ctx->h.bCnt == SKEIN_512_BLOCK_BYTES);
+            Skein_512_Process_Block(ctx,ctx->b,1,SKEIN_512_BLOCK_BYTES);
+            ctx->h.bCnt = 0;
+            }
+        /* now process any remaining full blocks, directly from input message data */
+        if (msgByteCnt > SKEIN_512_BLOCK_BYTES)
+            {
+            n = (msgByteCnt-1) / SKEIN_512_BLOCK_BYTES;   /* number of full blocks to process */
+            Skein_512_Process_Block(ctx,msg,n,SKEIN_512_BLOCK_BYTES);
+            msgByteCnt -= n * SKEIN_512_BLOCK_BYTES;
+            msg        += n * SKEIN_512_BLOCK_BYTES;
+            }
+        Skein_assert(ctx->h.bCnt == 0);
+        }
+
+    /* copy any remaining source message data bytes into b[] */
+    if (msgByteCnt)
+        {
+        Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES);
+        memcpy(&ctx->b[ctx->h.bCnt],msg,msgByteCnt);
+        ctx->h.bCnt += msgByteCnt;
+        }
+
+    return SKEIN_SUCCESS;
+    }
+   
+/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+/* finalize the hash computation and output the result */
+static int Skein_512_Final(Skein_512_Ctxt_t *ctx, u08b_t *hashVal)
+    {
+    size_t i,n,byteCnt;
+    u64b_t X[SKEIN_512_STATE_WORDS];
+    Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL);    /* catch uninitialized context */
+
+    ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL;                 /* tag as the final block */
+    if (ctx->h.bCnt < SKEIN_512_BLOCK_BYTES)            /* zero pad b[] if necessary */
+        memset(&ctx->b[ctx->h.bCnt],0,SKEIN_512_BLOCK_BYTES - ctx->h.bCnt);
+
+    Skein_512_Process_Block(ctx,ctx->b,1,ctx->h.bCnt);  /* process the final block */
+    
+    /* now output the result */
+    byteCnt = (ctx->h.hashBitLen + 7) >> 3;             /* total number of output bytes */
+
+    /* run Threefish in "counter mode" to generate output */
+    memset(ctx->b,0,sizeof(ctx->b));  /* zero out b[], so it can hold the counter */
+    memcpy(X,ctx->X,sizeof(X));       /* keep a local copy of counter mode "key" */
+    for (i=0;i*SKEIN_512_BLOCK_BYTES < byteCnt;i++)
+        {
+        ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */
+        Skein_Start_New_Type(ctx,OUT_FINAL);
+        Skein_512_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */
+        n = byteCnt - i*SKEIN_512_BLOCK_BYTES;   /* number of output bytes left to go */
+        if (n >= SKEIN_512_BLOCK_BYTES)
+            n  = SKEIN_512_BLOCK_BYTES;
+        Skein_Put64_LSB_First(hashVal+i*SKEIN_512_BLOCK_BYTES,ctx->X,n);   /* "output" the ctr mode bytes */
+        Skein_Show_Final(512,&ctx->h,n,hashVal+i*SKEIN_512_BLOCK_BYTES);
+        memcpy(ctx->X,X,sizeof(X));   /* restore the counter mode key for next time */
+        }
+    return SKEIN_SUCCESS;
+    }
+
+#if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF)
+static size_t Skein_512_API_CodeSize(void)
+    {
+    return ((u08b_t *) Skein_512_API_CodeSize) -
+           ((u08b_t *) Skein_512_Init);
+    }
+#endif
+
+/*****************************************************************/
+/*    1024-bit Skein                                             */
+/*****************************************************************/
+/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+/* init the context for a straight hashing operation  */
+static int Skein1024_Init(Skein1024_Ctxt_t *ctx, size_t hashBitLen)
+    {
+    union
+        {
+        u08b_t  b[SKEIN1024_STATE_BYTES];
+        u64b_t  w[SKEIN1024_STATE_WORDS];
+        } cfg;                              /* config block */
+        
+    Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN);
+    ctx->h.hashBitLen = hashBitLen;         /* output hash bit count */
+
+    switch (hashBitLen)
+        {              /* use pre-computed values, where available */
+#ifndef SKEIN_NO_PRECOMP
+        case  512: memcpy(ctx->X,SKEIN1024_IV_512 ,sizeof(ctx->X)); break;
+        case  384: memcpy(ctx->X,SKEIN1024_IV_384 ,sizeof(ctx->X)); break;
+        case 1024: memcpy(ctx->X,SKEIN1024_IV_1024,sizeof(ctx->X)); break;
+#endif
+        default:
+            /* here if there is no precomputed IV value available */
+            /* build/process the config block, type == CONFIG (could be precomputed) */
+            Skein_Start_New_Type(ctx,CFG_FINAL);        /* set tweaks: T0=0; T1=CFG | FINAL */
+
+            cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);  /* set the schema, version */
+            cfg.w[1] = Skein_Swap64(hashBitLen);        /* hash result length in bits */
+            cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL);
+            memset(&cfg.w[3],0,sizeof(cfg) - 3*sizeof(cfg.w[0])); /* zero pad config block */
+
+            /* compute the initial chaining values from config block */
+            memset(ctx->X,0,sizeof(ctx->X));            /* zero the chaining variables */
+            Skein1024_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN);
+            break;
+        }
+
+    /* The chaining vars ctx->X are now initialized for the given hashBitLen. */
+    /* Set up to process the data message portion of the hash (default) */
+    Skein_Start_New_Type(ctx,MSG);              /* T0=0, T1= MSG type */
+
+    return SKEIN_SUCCESS;
+    }
+
+#if 0
+/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+/* init the context for a MAC and/or tree hash operation */
+/* [identical to Skein1024_Init() when keyBytes == 0 && treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL] */
+static int Skein1024_InitExt(Skein1024_Ctxt_t *ctx,size_t hashBitLen,u64b_t treeInfo, const u08b_t *key, size_t keyBytes)
+    {
+    union
+        {
+        u08b_t  b[SKEIN1024_STATE_BYTES];
+        u64b_t  w[SKEIN1024_STATE_WORDS];
+        } cfg;                              /* config block */
+        
+    Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN);
+    Skein_Assert(keyBytes == 0 || key != NULL,SKEIN_FAIL);
+
+    /* compute the initial chaining values ctx->X[], based on key */
+    if (keyBytes == 0)                          /* is there a key? */
+        {                                   
+        memset(ctx->X,0,sizeof(ctx->X));        /* no key: use all zeroes as key for config block */
+        }
+    else                                        /* here to pre-process a key */
+        {
+        Skein_assert(sizeof(cfg.b) >= sizeof(ctx->X));
+        /* do a mini-Init right here */
+        ctx->h.hashBitLen=8*sizeof(ctx->X);     /* set output hash bit count = state size */
+        Skein_Start_New_Type(ctx,KEY);          /* set tweaks: T0 = 0; T1 = KEY type */
+        memset(ctx->X,0,sizeof(ctx->X));        /* zero the initial chaining variables */
+        Skein1024_Update(ctx,key,keyBytes);     /* hash the key */
+        Skein1024_Final_Pad(ctx,cfg.b);         /* put result into cfg.b[] */
+        memcpy(ctx->X,cfg.b,sizeof(cfg.b));     /* copy over into ctx->X[] */
+#if SKEIN_NEED_SWAP
+        {
+        uint_t i;
+        for (i=0;i<SKEIN1024_STATE_WORDS;i++)   /* convert key bytes to context words */
+            ctx->X[i] = Skein_Swap64(ctx->X[i]);
+        }
+#endif
+        }
+    /* build/process the config block, type == CONFIG (could be precomputed for each key) */
+    ctx->h.hashBitLen = hashBitLen;             /* output hash bit count */
+    Skein_Start_New_Type(ctx,CFG_FINAL);
+
+    memset(&cfg.w,0,sizeof(cfg.w));             /* pre-pad cfg.w[] with zeroes */
+    cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);
+    cfg.w[1] = Skein_Swap64(hashBitLen);        /* hash result length in bits */
+    cfg.w[2] = Skein_Swap64(treeInfo);          /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */
+
+    Skein_Show_Key(1024,&ctx->h,key,keyBytes);
+
+    /* compute the initial chaining values from config block */
+    Skein1024_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN);
+
+    /* The chaining vars ctx->X are now initialized */
+    /* Set up to process the data message portion of the hash (default) */
+    ctx->h.bCnt = 0;                            /* buffer b[] starts out empty */
+    Skein_Start_New_Type(ctx,MSG);
+    
+    return SKEIN_SUCCESS;
+    }
+#endif
+
+/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+/* process the input bytes */
+static int Skein1024_Update(Skein1024_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt)
+    {
+    size_t n;
+
+    Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES,SKEIN_FAIL);    /* catch uninitialized context */
+
+    /* process full blocks, if any */
+    if (msgByteCnt + ctx->h.bCnt > SKEIN1024_BLOCK_BYTES)
+        {
+        if (ctx->h.bCnt)                              /* finish up any buffered message data */
+            {
+            n = SKEIN1024_BLOCK_BYTES - ctx->h.bCnt;  /* # bytes free in buffer b[] */
+            if (n)
+                {
+                Skein_assert(n < msgByteCnt);         /* check on our logic here */
+                memcpy(&ctx->b[ctx->h.bCnt],msg,n);
+                msgByteCnt  -= n;
+                msg         += n;
+                ctx->h.bCnt += n;
+                }
+            Skein_assert(ctx->h.bCnt == SKEIN1024_BLOCK_BYTES);
+            Skein1024_Process_Block(ctx,ctx->b,1,SKEIN1024_BLOCK_BYTES);
+            ctx->h.bCnt = 0;
+            }
+        /* now process any remaining full blocks, directly from input message data */
+        if (msgByteCnt > SKEIN1024_BLOCK_BYTES)
+            {
+            n = (msgByteCnt-1) / SKEIN1024_BLOCK_BYTES;   /* number of full blocks to process */
+            Skein1024_Process_Block(ctx,msg,n,SKEIN1024_BLOCK_BYTES);
+            msgByteCnt -= n * SKEIN1024_BLOCK_BYTES;
+            msg        += n * SKEIN1024_BLOCK_BYTES;
+            }
+        Skein_assert(ctx->h.bCnt == 0);
+        }
+
+    /* copy any remaining source message data bytes into b[] */
+    if (msgByteCnt)
+        {
+        Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES);
+        memcpy(&ctx->b[ctx->h.bCnt],msg,msgByteCnt);
+        ctx->h.bCnt += msgByteCnt;
+        }
+
+    return SKEIN_SUCCESS;
+    }
+   
+/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+/* finalize the hash computation and output the result */
+static int Skein1024_Final(Skein1024_Ctxt_t *ctx, u08b_t *hashVal)
+    {
+    size_t i,n,byteCnt;
+    u64b_t X[SKEIN1024_STATE_WORDS];
+    Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES,SKEIN_FAIL);    /* catch uninitialized context */
+
+    ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL;                 /* tag as the final block */
+    if (ctx->h.bCnt < SKEIN1024_BLOCK_BYTES)            /* zero pad b[] if necessary */
+        memset(&ctx->b[ctx->h.bCnt],0,SKEIN1024_BLOCK_BYTES - ctx->h.bCnt);
+
+    Skein1024_Process_Block(ctx,ctx->b,1,ctx->h.bCnt);  /* process the final block */
+    
+    /* now output the result */
+    byteCnt = (ctx->h.hashBitLen + 7) >> 3;             /* total number of output bytes */
+
+    /* run Threefish in "counter mode" to generate output */
+    memset(ctx->b,0,sizeof(ctx->b));  /* zero out b[], so it can hold the counter */
+    memcpy(X,ctx->X,sizeof(X));       /* keep a local copy of counter mode "key" */
+    for (i=0;i*SKEIN1024_BLOCK_BYTES < byteCnt;i++)
+        {
+        ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */
+        Skein_Start_New_Type(ctx,OUT_FINAL);
+        Skein1024_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */
+        n = byteCnt - i*SKEIN1024_BLOCK_BYTES;   /* number of output bytes left to go */
+        if (n >= SKEIN1024_BLOCK_BYTES)
+            n  = SKEIN1024_BLOCK_BYTES;
+        Skein_Put64_LSB_First(hashVal+i*SKEIN1024_BLOCK_BYTES,ctx->X,n);   /* "output" the ctr mode bytes */
+        Skein_Show_Final(1024,&ctx->h,n,hashVal+i*SKEIN1024_BLOCK_BYTES);
+        memcpy(ctx->X,X,sizeof(X));   /* restore the counter mode key for next time */
+        }
+    return SKEIN_SUCCESS;
+    }
+
+#if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF)
+static size_t Skein1024_API_CodeSize(void)
+    {
+    return ((u08b_t *) Skein1024_API_CodeSize) -
+           ((u08b_t *) Skein1024_Init);
+    }
+#endif
+
+/**************** Functions to support MAC/tree hashing ***************/
+/*   (this code is identical for Optimized and Reference versions)    */
+
+#if 0
+/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+/* finalize the hash computation and output the block, no OUTPUT stage */
+static int Skein_256_Final_Pad(Skein_256_Ctxt_t *ctx, u08b_t *hashVal)
+    {
+    Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES,SKEIN_FAIL);    /* catch uninitialized context */
+
+    ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL;        /* tag as the final block */
+    if (ctx->h.bCnt < SKEIN_256_BLOCK_BYTES)   /* zero pad b[] if necessary */
+        memset(&ctx->b[ctx->h.bCnt],0,SKEIN_256_BLOCK_BYTES - ctx->h.bCnt);
+    Skein_256_Process_Block(ctx,ctx->b,1,ctx->h.bCnt);    /* process the final block */
+    
+    Skein_Put64_LSB_First(hashVal,ctx->X,SKEIN_256_BLOCK_BYTES);   /* "output" the state bytes */
+    
+    return SKEIN_SUCCESS;
+    }
+
+/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+/* finalize the hash computation and output the block, no OUTPUT stage */
+static int Skein_512_Final_Pad(Skein_512_Ctxt_t *ctx, u08b_t *hashVal)
+    {
+    Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL);    /* catch uninitialized context */
+
+    ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL;        /* tag as the final block */
+    if (ctx->h.bCnt < SKEIN_512_BLOCK_BYTES)   /* zero pad b[] if necessary */
+        memset(&ctx->b[ctx->h.bCnt],0,SKEIN_512_BLOCK_BYTES - ctx->h.bCnt);
+    Skein_512_Process_Block(ctx,ctx->b,1,ctx->h.bCnt);    /* process the final block */
+    
+    Skein_Put64_LSB_First(hashVal,ctx->X,SKEIN_512_BLOCK_BYTES);   /* "output" the state bytes */
+    
+    return SKEIN_SUCCESS;
+    }
+
+/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+/* finalize the hash computation and output the block, no OUTPUT stage */
+static int Skein1024_Final_Pad(Skein1024_Ctxt_t *ctx, u08b_t *hashVal)
+    {
+    Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES,SKEIN_FAIL);    /* catch uninitialized context */
+
+    ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL;        /* tag as the final block */
+    if (ctx->h.bCnt < SKEIN1024_BLOCK_BYTES)   /* zero pad b[] if necessary */
+        memset(&ctx->b[ctx->h.bCnt],0,SKEIN1024_BLOCK_BYTES - ctx->h.bCnt);
+    Skein1024_Process_Block(ctx,ctx->b,1,ctx->h.bCnt);    /* process the final block */
+    
+    Skein_Put64_LSB_First(hashVal,ctx->X,SKEIN1024_BLOCK_BYTES);   /* "output" the state bytes */
+    
+    return SKEIN_SUCCESS;
+    }
+
+
+#if SKEIN_TREE_HASH
+/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+/* just do the OUTPUT stage                                       */
+static int Skein_256_Output(Skein_256_Ctxt_t *ctx, u08b_t *hashVal)
+    {
+    size_t i,n,byteCnt;
+    u64b_t X[SKEIN_256_STATE_WORDS];
+    Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES,SKEIN_FAIL);    /* catch uninitialized context */
+
+    /* now output the result */
+    byteCnt = (ctx->h.hashBitLen + 7) >> 3;    /* total number of output bytes */
+
+    /* run Threefish in "counter mode" to generate output */
+    memset(ctx->b,0,sizeof(ctx->b));  /* zero out b[], so it can hold the counter */
+    memcpy(X,ctx->X,sizeof(X));       /* keep a local copy of counter mode "key" */
+    for (i=0;i*SKEIN_256_BLOCK_BYTES < byteCnt;i++)
+        {
+        ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */
+        Skein_Start_New_Type(ctx,OUT_FINAL);
+        Skein_256_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */
+        n = byteCnt - i*SKEIN_256_BLOCK_BYTES;   /* number of output bytes left to go */
+        if (n >= SKEIN_256_BLOCK_BYTES)
+            n  = SKEIN_256_BLOCK_BYTES;
+        Skein_Put64_LSB_First(hashVal+i*SKEIN_256_BLOCK_BYTES,ctx->X,n);   /* "output" the ctr mode bytes */
+        Skein_Show_Final(256,&ctx->h,n,hashVal+i*SKEIN_256_BLOCK_BYTES);
+        memcpy(ctx->X,X,sizeof(X));   /* restore the counter mode key for next time */
+        }
+    return SKEIN_SUCCESS;
+    }
+
+/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+/* just do the OUTPUT stage                                       */
+static int Skein_512_Output(Skein_512_Ctxt_t *ctx, u08b_t *hashVal)
+    {
+    size_t i,n,byteCnt;
+    u64b_t X[SKEIN_512_STATE_WORDS];
+    Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL);    /* catch uninitialized context */
+
+    /* now output the result */
+    byteCnt = (ctx->h.hashBitLen + 7) >> 3;    /* total number of output bytes */
+
+    /* run Threefish in "counter mode" to generate output */
+    memset(ctx->b,0,sizeof(ctx->b));  /* zero out b[], so it can hold the counter */
+    memcpy(X,ctx->X,sizeof(X));       /* keep a local copy of counter mode "key" */
+    for (i=0;i*SKEIN_512_BLOCK_BYTES < byteCnt;i++)
+        {
+        ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */
+        Skein_Start_New_Type(ctx,OUT_FINAL);
+        Skein_512_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */
+        n = byteCnt - i*SKEIN_512_BLOCK_BYTES;   /* number of output bytes left to go */
+        if (n >= SKEIN_512_BLOCK_BYTES)
+            n  = SKEIN_512_BLOCK_BYTES;
+        Skein_Put64_LSB_First(hashVal+i*SKEIN_512_BLOCK_BYTES,ctx->X,n);   /* "output" the ctr mode bytes */
+        Skein_Show_Final(256,&ctx->h,n,hashVal+i*SKEIN_512_BLOCK_BYTES);
+        memcpy(ctx->X,X,sizeof(X));   /* restore the counter mode key for next time */
+        }
+    return SKEIN_SUCCESS;
+    }
+
+/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+/* just do the OUTPUT stage                                       */
+static int Skein1024_Output(Skein1024_Ctxt_t *ctx, u08b_t *hashVal)
+    {
+    size_t i,n,byteCnt;
+    u64b_t X[SKEIN1024_STATE_WORDS];
+    Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES,SKEIN_FAIL);    /* catch uninitialized context */
+
+    /* now output the result */
+    byteCnt = (ctx->h.hashBitLen + 7) >> 3;    /* total number of output bytes */
+
+    /* run Threefish in "counter mode" to generate output */
+    memset(ctx->b,0,sizeof(ctx->b));  /* zero out b[], so it can hold the counter */
+    memcpy(X,ctx->X,sizeof(X));       /* keep a local copy of counter mode "key" */
+    for (i=0;i*SKEIN1024_BLOCK_BYTES < byteCnt;i++)
+        {
+        ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */
+        Skein_Start_New_Type(ctx,OUT_FINAL);
+        Skein1024_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */
+        n = byteCnt - i*SKEIN1024_BLOCK_BYTES;   /* number of output bytes left to go */
+        if (n >= SKEIN1024_BLOCK_BYTES)
+            n  = SKEIN1024_BLOCK_BYTES;
+        Skein_Put64_LSB_First(hashVal+i*SKEIN1024_BLOCK_BYTES,ctx->X,n);   /* "output" the ctr mode bytes */
+        Skein_Show_Final(256,&ctx->h,n,hashVal+i*SKEIN1024_BLOCK_BYTES);
+        memcpy(ctx->X,X,sizeof(X));   /* restore the counter mode key for next time */
+        }
+    return SKEIN_SUCCESS;
+    }
+#endif
+#endif
+
+typedef struct
+{
+  uint_t  statebits;                      /* 256, 512, or 1024 */
+  union
+  {
+    Skein_Ctxt_Hdr_t h;                 /* common header "overlay" */
+    Skein_256_Ctxt_t ctx_256;
+    Skein_512_Ctxt_t ctx_512;
+    Skein1024_Ctxt_t ctx1024;
+  } u;
+}
+hashState;
+
+/* "incremental" hashing API */
+static HashReturn Init  (hashState *state, int hashbitlen);
+static HashReturn Update(hashState *state, const BitSequence *data, DataLength databitlen);
+static HashReturn Final (hashState *state,       BitSequence *hashval);
+
+/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+/* select the context size and init the context */
+static HashReturn Init(hashState *state, int hashbitlen)
+{
+#if SKEIN_256_NIST_MAX_HASHBITS
+  if (hashbitlen <= SKEIN_256_NIST_MAX_HASHBITS)
+  {
+    Skein_Assert(hashbitlen > 0,BAD_HASHLEN);
+    state->statebits = 64*SKEIN_256_STATE_WORDS;
+    return Skein_256_Init(&state->u.ctx_256,(size_t) hashbitlen);
+  }
+#endif
+  if (hashbitlen <= SKEIN_512_NIST_MAX_HASHBITS)
+  {
+    state->statebits = 64*SKEIN_512_STATE_WORDS;
+    return Skein_512_Init(&state->u.ctx_512,(size_t) hashbitlen);
+  }
+  else
+  {
+    state->statebits = 64*SKEIN1024_STATE_WORDS;
+    return Skein1024_Init(&state->u.ctx1024,(size_t) hashbitlen);
+  }
+}
+
+/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+/* process data to be hashed */
+static HashReturn Update(hashState *state, const BitSequence *data, DataLength databitlen)
+{
+  /* only the final Update() call is allowed do partial bytes, else assert an error */
+  Skein_Assert((state->u.h.T[1] & SKEIN_T1_FLAG_BIT_PAD) == 0 || databitlen == 0, SKEIN_FAIL);
+
+  Skein_Assert(state->statebits % 256 == 0 && (state->statebits-256) < 1024,SKEIN_FAIL);
+  if ((databitlen & 7) == 0)  /* partial bytes? */
+  {
+    switch ((state->statebits >> 8) & 3)
+    {
+    case 2:  return Skein_512_Update(&state->u.ctx_512,data,databitlen >> 3);
+    case 1:  return Skein_256_Update(&state->u.ctx_256,data,databitlen >> 3);
+    case 0:  return Skein1024_Update(&state->u.ctx1024,data,databitlen >> 3);
+    default: return SKEIN_FAIL;
+    }
+  }
+  else
+  {   /* handle partial final byte */
+    size_t bCnt = (databitlen >> 3) + 1;                  /* number of bytes to handle (nonzero here!) */
+    u08b_t b,mask;
+
+    mask = (u08b_t) (1u << (7 - (databitlen & 7)));       /* partial byte bit mask */
+    b    = (u08b_t) ((data[bCnt-1] & (0-mask)) | mask);   /* apply bit padding on final byte */
+
+    switch ((state->statebits >> 8) & 3)
+    {
+    case 2:  Skein_512_Update(&state->u.ctx_512,data,bCnt-1); /* process all but the final byte    */
+      Skein_512_Update(&state->u.ctx_512,&b  ,  1   ); /* process the (masked) partial byte */
+      break;
+    case 1:  Skein_256_Update(&state->u.ctx_256,data,bCnt-1); /* process all but the final byte    */
+      Skein_256_Update(&state->u.ctx_256,&b  ,  1   ); /* process the (masked) partial byte */
+      break;
+    case 0:  Skein1024_Update(&state->u.ctx1024,data,bCnt-1); /* process all but the final byte    */
+      Skein1024_Update(&state->u.ctx1024,&b  ,  1   ); /* process the (masked) partial byte */
+      break;
+    default: return SKEIN_FAIL;
+    }
+    Skein_Set_Bit_Pad_Flag(state->u.h);                    /* set tweak flag for the final call */
+
+    return SKEIN_SUCCESS;
+  }
+}
+
+/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+/* finalize hash computation and output the result (hashbitlen bits) */
+static HashReturn Final(hashState *state, BitSequence *hashval)
+{
+  Skein_Assert(state->statebits % 256 == 0 && (state->statebits-256) < 1024,FAIL);
+  switch ((state->statebits >> 8) & 3)
+  {
+  case 2:  return Skein_512_Final(&state->u.ctx_512,hashval);
+  case 1:  return Skein_256_Final(&state->u.ctx_256,hashval);
+  case 0:  return Skein1024_Final(&state->u.ctx1024,hashval);
+  default: return SKEIN_FAIL;
+  }
+}
+
+/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+/* all-in-one hash function */
+HashReturn skein_hash(int hashbitlen, const BitSequence *data, /* all-in-one call */
+                DataLength databitlen,BitSequence *hashval)
+{
+  hashState  state;
+  HashReturn r = Init(&state,hashbitlen);
+  if (r == SKEIN_SUCCESS)
+  { /* these calls do not fail when called properly */
+    r = Update(&state,data,databitlen);
+    Final(&state,hashval);
+  }
+  return r;
+}
diff --git a/crypt/monero_crypto/skein.h b/crypt/monero_crypto/skein.h
new file mode 100644
index 0000000000..5c9cc55183
--- /dev/null
+++ b/crypt/monero_crypto/skein.h
@@ -0,0 +1,47 @@
+#ifndef _SKEIN_H_
+#define _SKEIN_H_     1
+/**************************************************************************
+**
+** Interface declarations and internal definitions for Skein hashing.
+**
+** Source code author: Doug Whiting, 2008.
+**
+** This algorithm and source code is released to the public domain.
+**
+***************************************************************************
+** 
+** The following compile-time switches may be defined to control some
+** tradeoffs between speed, code size, error checking, and security.
+**
+** The "default" note explains what happens when the switch is not defined.
+**
+**  SKEIN_DEBUG            -- make callouts from inside Skein code
+**                            to examine/display intermediate values.
+**                            [default: no callouts (no overhead)]
+**
+**  SKEIN_ERR_CHECK        -- how error checking is handled inside Skein
+**                            code. If not defined, most error checking 
+**                            is disabled (for performance). Otherwise, 
+**                            the switch value is interpreted as:
+**                                0: use assert()      to flag errors
+**                                1: return SKEIN_FAIL to flag errors
+**
+***************************************************************************/
+#include "skein_port.h"                      /* get platform-specific definitions */
+
+typedef enum
+{
+  SKEIN_SUCCESS         =      0,          /* return codes from Skein calls */
+  SKEIN_FAIL            =      1,
+  SKEIN_BAD_HASHLEN     =      2
+}
+HashReturn;
+
+typedef size_t   DataLength;                /* bit count  type */
+typedef u08b_t   BitSequence;               /* bit stream type */
+
+/* "all-in-one" call */
+HashReturn skein_hash(int hashbitlen,   const BitSequence *data, 
+                      DataLength databitlen,  BitSequence *hashval);
+
+#endif  /* ifndef _SKEIN_H_ */
diff --git a/crypt/monero_crypto/skein_port.h b/crypt/monero_crypto/skein_port.h
new file mode 100644
index 0000000000..a06ef30a26
--- /dev/null
+++ b/crypt/monero_crypto/skein_port.h
@@ -0,0 +1,218 @@
+// 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.
+
+#ifndef _SKEIN_PORT_H_
+#define _SKEIN_PORT_H_
+
+#include <limits.h>
+#include <stdint.h>
+
+#ifndef RETURN_VALUES
+#  define RETURN_VALUES
+#  if defined( DLL_EXPORT )
+#    if defined( _MSC_VER ) || defined ( __INTEL_COMPILER )
+#      define VOID_RETURN    __declspec( dllexport ) void __stdcall
+#      define INT_RETURN     __declspec( dllexport ) int  __stdcall
+#    elif defined( __GNUC__ )
+#      define VOID_RETURN    __declspec( __dllexport__ ) void
+#      define INT_RETURN     __declspec( __dllexport__ ) int
+#    else
+#      error Use of the DLL is only available on the Microsoft, Intel and GCC compilers
+#    endif
+#  elif defined( DLL_IMPORT )
+#    if defined( _MSC_VER ) || defined ( __INTEL_COMPILER )
+#      define VOID_RETURN    __declspec( dllimport ) void __stdcall
+#      define INT_RETURN     __declspec( dllimport ) int  __stdcall
+#    elif defined( __GNUC__ )
+#      define VOID_RETURN    __declspec( __dllimport__ ) void
+#      define INT_RETURN     __declspec( __dllimport__ ) int
+#    else
+#      error Use of the DLL is only available on the Microsoft, Intel and GCC compilers
+#    endif
+#  elif defined( __WATCOMC__ )
+#    define VOID_RETURN  void __cdecl
+#    define INT_RETURN   int  __cdecl
+#  else
+#    define VOID_RETURN  void
+#    define INT_RETURN   int
+#  endif
+#endif
+
+/*  These defines are used to declare buffers in a way that allows
+    faster operations on longer variables to be used.  In all these
+    defines 'size' must be a power of 2 and >= 8
+
+    dec_unit_type(size,x)       declares a variable 'x' of length 
+                                'size' bits
+
+    dec_bufr_type(size,bsize,x) declares a buffer 'x' of length 'bsize' 
+                                bytes defined as an array of variables
+                                each of 'size' bits (bsize must be a 
+                                multiple of size / 8)
+
+    ptr_cast(x,size)            casts a pointer to a pointer to a 
+                                varaiable of length 'size' bits
+*/
+
+#define ui_type(size)               uint##size##_t
+#define dec_unit_type(size,x)       typedef ui_type(size) x
+#define dec_bufr_type(size,bsize,x) typedef ui_type(size) x[bsize / (size >> 3)]
+#define ptr_cast(x,size)            ((ui_type(size)*)(x))
+
+typedef unsigned int    uint_t;             /* native unsigned integer */
+typedef uint8_t         u08b_t;             /*  8-bit unsigned integer */
+typedef uint64_t        u64b_t;             /* 64-bit unsigned integer */
+
+#ifndef RotL_64
+#define RotL_64(x,N)    (((x) << (N)) | ((x) >> (64-(N))))
+#endif
+
+/*
+ * Skein is "natively" little-endian (unlike SHA-xxx), for optimal
+ * performance on x86 CPUs.  The Skein code requires the following
+ * definitions for dealing with endianness:
+ *
+ *    SKEIN_NEED_SWAP:  0 for little-endian, 1 for big-endian
+ *    Skein_Put64_LSB_First
+ *    Skein_Get64_LSB_First
+ *    Skein_Swap64
+ *
+ * If SKEIN_NEED_SWAP is defined at compile time, it is used here
+ * along with the portable versions of Put64/Get64/Swap64, which 
+ * are slow in general.
+ *
+ * Otherwise, an "auto-detect" of endianness is attempted below.
+ * If the default handling doesn't work well, the user may insert
+ * platform-specific code instead (e.g., for big-endian CPUs).
+ *
+ */
+#ifndef SKEIN_NEED_SWAP /* compile-time "override" for endianness? */
+
+
+#include "common/int-util.h"
+
+#define IS_BIG_ENDIAN      4321 /* byte 0 is most significant (mc68k) */
+#define IS_LITTLE_ENDIAN   1234 /* byte 0 is least significant (i386) */
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#  define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
+#endif
+
+#if BYTE_ORDER == BIG_ENDIAN
+#  define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
+#endif
+
+/* special handler for IA64, which may be either endianness (?)  */
+/* here we assume little-endian, but this may need to be changed */
+#if defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
+#  define PLATFORM_MUST_ALIGN (1)
+#ifndef PLATFORM_BYTE_ORDER
+#  define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
+#endif
+#endif
+
+#ifndef   PLATFORM_MUST_ALIGN
+#  define PLATFORM_MUST_ALIGN (0)
+#endif
+
+
+#if   PLATFORM_BYTE_ORDER == IS_BIG_ENDIAN
+    /* here for big-endian CPUs */
+#define SKEIN_NEED_SWAP   (1)
+#elif PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN
+    /* here for x86 and x86-64 CPUs (and other detected little-endian CPUs) */
+#define SKEIN_NEED_SWAP   (0)
+#if   PLATFORM_MUST_ALIGN == 0              /* ok to use "fast" versions? */
+#define Skein_Put64_LSB_First(dst08,src64,bCnt) memcpy(dst08,src64,bCnt)
+#define Skein_Get64_LSB_First(dst64,src08,wCnt) memcpy(dst64,src08,8*(wCnt))
+#endif
+#else
+#error "Skein needs endianness setting!"
+#endif
+
+#endif /* ifndef SKEIN_NEED_SWAP */
+
+/*
+ ******************************************************************
+ *      Provide any definitions still needed.
+ ******************************************************************
+ */
+#ifndef Skein_Swap64  /* swap for big-endian, nop for little-endian */
+#if     SKEIN_NEED_SWAP
+#define Skein_Swap64(w64)                       \
+  ( (( ((u64b_t)(w64))       & 0xFF) << 56) |   \
+    (((((u64b_t)(w64)) >> 8) & 0xFF) << 48) |   \
+    (((((u64b_t)(w64)) >>16) & 0xFF) << 40) |   \
+    (((((u64b_t)(w64)) >>24) & 0xFF) << 32) |   \
+    (((((u64b_t)(w64)) >>32) & 0xFF) << 24) |   \
+    (((((u64b_t)(w64)) >>40) & 0xFF) << 16) |   \
+    (((((u64b_t)(w64)) >>48) & 0xFF) <<  8) |   \
+    (((((u64b_t)(w64)) >>56) & 0xFF)      ) )
+#else
+#define Skein_Swap64(w64)  (w64)
+#endif
+#endif  /* ifndef Skein_Swap64 */
+
+
+#ifndef Skein_Put64_LSB_First
+void    Skein_Put64_LSB_First(u08b_t *dst,const u64b_t *src,size_t bCnt)
+#ifdef  SKEIN_PORT_CODE /* instantiate the function code here? */
+    { /* this version is fully portable (big-endian or little-endian), but slow */
+    size_t n;
+
+    for (n=0;n<bCnt;n++)
+        dst[n] = (u08b_t) (src[n>>3] >> (8*(n&7)));
+    }
+#else
+    ;    /* output only the function prototype */
+#endif
+#endif   /* ifndef Skein_Put64_LSB_First */
+
+
+#ifndef Skein_Get64_LSB_First
+void    Skein_Get64_LSB_First(u64b_t *dst,const u08b_t *src,size_t wCnt)
+#ifdef  SKEIN_PORT_CODE /* instantiate the function code here? */
+    { /* this version is fully portable (big-endian or little-endian), but slow */
+    size_t n;
+
+    for (n=0;n<8*wCnt;n+=8)
+        dst[n/8] = (((u64b_t) src[n  ])      ) +
+                   (((u64b_t) src[n+1]) <<  8) +
+                   (((u64b_t) src[n+2]) << 16) +
+                   (((u64b_t) src[n+3]) << 24) +
+                   (((u64b_t) src[n+4]) << 32) +
+                   (((u64b_t) src[n+5]) << 40) +
+                   (((u64b_t) src[n+6]) << 48) +
+                   (((u64b_t) src[n+7]) << 56) ;
+    }
+#else
+    ;    /* output only the function prototype */
+#endif
+#endif   /* ifndef Skein_Get64_LSB_First */
+
+#endif   /* ifndef _SKEIN_PORT_H_ */
diff --git a/crypt/monero_crypto/slow-hash.c b/crypt/monero_crypto/slow-hash.c
new file mode 100644
index 0000000000..cc234713b8
--- /dev/null
+++ b/crypt/monero_crypto/slow-hash.c
@@ -0,0 +1,1284 @@
+// 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
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "common/int-util.h"
+#include "hash-ops.h"
+#include "oaes_lib.h"
+
+#define MEMORY         (1 << 21) // 2MB scratchpad
+#define ITER           (1 << 20)
+#define AES_BLOCK_SIZE  16
+#define AES_KEY_SIZE    32
+#define INIT_SIZE_BLK   8
+#define INIT_SIZE_BYTE (INIT_SIZE_BLK * AES_BLOCK_SIZE)
+
+extern int aesb_single_round(const uint8_t *in, uint8_t*out, const uint8_t *expandedKey);
+extern int aesb_pseudo_round(const uint8_t *in, uint8_t *out, const uint8_t *expandedKey);
+
+#if !defined NO_AES && (defined(__x86_64__) || (defined(_MSC_VER) && defined(_WIN64)))
+// Optimised code below, uses x86-specific intrinsics, SSE2, AES-NI
+// Fall back to more portable code is down at the bottom
+
+#include <emmintrin.h>
+
+#if defined(_MSC_VER)
+#include <intrin.h>
+#include <windows.h>
+#define STATIC
+#define INLINE __inline
+#if !defined(RDATA_ALIGN16)
+#define RDATA_ALIGN16 __declspec(align(16))
+#endif
+#elif defined(__MINGW32__)
+#include <intrin.h>
+#include <windows.h>
+#define STATIC static
+#define INLINE inline
+#if !defined(RDATA_ALIGN16)
+#define RDATA_ALIGN16 __attribute__ ((aligned(16)))
+#endif
+#else
+#include <wmmintrin.h>
+#include <sys/mman.h>
+#define STATIC static
+#define INLINE inline
+#if !defined(RDATA_ALIGN16)
+#define RDATA_ALIGN16 __attribute__ ((aligned(16)))
+#endif
+#endif
+
+#if defined(__INTEL_COMPILER)
+#define ASM __asm__
+#elif !defined(_MSC_VER)
+#define ASM __asm__
+#else
+#define ASM __asm
+#endif
+
+#define TOTALBLOCKS (MEMORY / AES_BLOCK_SIZE)
+
+#define U64(x) ((uint64_t *) (x))
+#define R128(x) ((__m128i *) (x))
+
+#define state_index(x) (((*((uint64_t *)x) >> 4) & (TOTALBLOCKS - 1)) << 4)
+#if defined(_MSC_VER)
+#if !defined(_WIN64)
+#define __mul() lo = mul128(c[0], b[0], &hi);
+#else
+#define __mul() lo = _umul128(c[0], b[0], &hi);
+#endif
+#else
+#if defined(__x86_64__)
+#define __mul() ASM("mulq %3\n\t" : "=d"(hi), "=a"(lo) : "%a" (c[0]), "rm" (b[0]) : "cc");
+#else
+#define __mul() lo = mul128(c[0], b[0], &hi);
+#endif
+#endif
+
+#define pre_aes() \
+  j = state_index(a); \
+  _c = _mm_load_si128(R128(&hp_state[j])); \
+  _a = _mm_load_si128(R128(a)); \
+
+/*
+ * An SSE-optimized implementation of the second half of CryptoNight step 3.
+ * After using AES to mix a scratchpad value into _c (done by the caller),
+ * this macro xors it with _b and stores the result back to the same index (j) that it
+ * loaded the scratchpad value from.  It then performs a second random memory
+ * read/write from the scratchpad, but this time mixes the values using a 64
+ * bit multiply.
+ * This code is based upon an optimized implementation by dga.
+ */
+#define post_aes() \
+  _mm_store_si128(R128(c), _c); \
+  _b = _mm_xor_si128(_b, _c); \
+  _mm_store_si128(R128(&hp_state[j]), _b); \
+  j = state_index(c); \
+  p = U64(&hp_state[j]); \
+  b[0] = p[0]; b[1] = p[1]; \
+  __mul(); \
+  a[0] += hi; a[1] += lo; \
+  p = U64(&hp_state[j]); \
+  p[0] = a[0];  p[1] = a[1]; \
+  a[0] ^= b[0]; a[1] ^= b[1]; \
+  _b = _c; \
+
+#if defined(_MSC_VER)
+#define THREADV __declspec(thread)
+#else
+#define THREADV __thread
+#endif
+
+#pragma pack(push, 1)
+union cn_slow_hash_state
+{
+    union hash_state hs;
+    struct
+    {
+        uint8_t k[64];
+        uint8_t init[INIT_SIZE_BYTE];
+    };
+};
+#pragma pack(pop)
+
+THREADV uint8_t *hp_state = NULL;
+THREADV int hp_allocated = 0;
+
+#if defined(_MSC_VER)
+#define cpuid(info,x)    __cpuidex(info,x,0)
+#else
+void cpuid(int CPUInfo[4], int InfoType)
+{
+    ASM __volatile__
+    (
+    "cpuid":
+        "=a" (CPUInfo[0]),
+        "=b" (CPUInfo[1]),
+        "=c" (CPUInfo[2]),
+        "=d" (CPUInfo[3]) :
+            "a" (InfoType), "c" (0)
+        );
+}
+#endif
+
+/**
+ * @brief a = (a xor b), where a and b point to 128 bit values
+ */
+
+STATIC INLINE void xor_blocks(uint8_t *a, const uint8_t *b)
+{
+    U64(a)[0] ^= U64(b)[0];
+    U64(a)[1] ^= U64(b)[1];
+}
+
+/**
+ * @brief uses cpuid to determine if the CPU supports the AES instructions
+ * @return true if the CPU supports AES, false otherwise
+ */
+
+STATIC INLINE int force_software_aes(void)
+{
+  static int use = -1;
+
+  if (use != -1)
+    return use;
+
+  const char *env = getenv("MONERO_USE_SOFTWARE_AES");
+  if (!env) {
+    use = 0;
+  }
+  else if (!strcmp(env, "0") || !strcmp(env, "no")) {
+    use = 0;
+  }
+  else {
+    use = 1;
+  }
+  return use;
+}
+
+STATIC INLINE int check_aes_hw(void)
+{
+    int cpuid_results[4];
+    static int supported = -1;
+
+    if(supported >= 0)
+        return supported;
+
+    cpuid(cpuid_results,1);
+    return supported = cpuid_results[2] & (1 << 25);
+}
+
+STATIC INLINE void aes_256_assist1(__m128i* t1, __m128i * t2)
+{
+    __m128i t4;
+    *t2 = _mm_shuffle_epi32(*t2, 0xff);
+    t4 = _mm_slli_si128(*t1, 0x04);
+    *t1 = _mm_xor_si128(*t1, t4);
+    t4 = _mm_slli_si128(t4, 0x04);
+    *t1 = _mm_xor_si128(*t1, t4);
+    t4 = _mm_slli_si128(t4, 0x04);
+    *t1 = _mm_xor_si128(*t1, t4);
+    *t1 = _mm_xor_si128(*t1, *t2);
+}
+
+STATIC INLINE void aes_256_assist2(__m128i* t1, __m128i * t3)
+{
+    __m128i t2, t4;
+    t4 = _mm_aeskeygenassist_si128(*t1, 0x00);
+    t2 = _mm_shuffle_epi32(t4, 0xaa);
+    t4 = _mm_slli_si128(*t3, 0x04);
+    *t3 = _mm_xor_si128(*t3, t4);
+    t4 = _mm_slli_si128(t4, 0x04);
+    *t3 = _mm_xor_si128(*t3, t4);
+    t4 = _mm_slli_si128(t4, 0x04);
+    *t3 = _mm_xor_si128(*t3, t4);
+    *t3 = _mm_xor_si128(*t3, t2);
+}
+
+/**
+ * @brief expands 'key' into a form it can be used for AES encryption.
+ *
+ * This is an SSE-optimized implementation of AES key schedule generation.  It
+ * expands the key into multiple round keys, each of which is used in one round
+ * of the AES encryption used to fill (and later, extract randomness from)
+ * the large 2MB buffer.  Note that CryptoNight does not use a completely
+ * standard AES encryption for its buffer expansion, so do not copy this
+ * function outside of Monero without caution!  This version uses the hardware
+ * AESKEYGENASSIST instruction to speed key generation, and thus requires
+ * CPU AES support.
+ * For more information about these functions, see page 19 of Intel's AES instructions
+ * white paper:
+ * http://www.intel.com/content/dam/www/public/us/en/documents/white-papers/aes-instructions-set-white-paper.pdf
+ *
+ * @param key the input 128 bit key
+ * @param expandedKey An output buffer to hold the generated key schedule
+ */
+
+STATIC INLINE void aes_expand_key(const uint8_t *key, uint8_t *expandedKey)
+{
+    __m128i *ek = R128(expandedKey);
+    __m128i t1, t2, t3;
+
+    t1 = _mm_loadu_si128(R128(key));
+    t3 = _mm_loadu_si128(R128(key + 16));
+
+    ek[0] = t1;
+    ek[1] = t3;
+
+    t2 = _mm_aeskeygenassist_si128(t3, 0x01);
+    aes_256_assist1(&t1, &t2);
+    ek[2] = t1;
+    aes_256_assist2(&t1, &t3);
+    ek[3] = t3;
+
+    t2 = _mm_aeskeygenassist_si128(t3, 0x02);
+    aes_256_assist1(&t1, &t2);
+    ek[4] = t1;
+    aes_256_assist2(&t1, &t3);
+    ek[5] = t3;
+
+    t2 = _mm_aeskeygenassist_si128(t3, 0x04);
+    aes_256_assist1(&t1, &t2);
+    ek[6] = t1;
+    aes_256_assist2(&t1, &t3);
+    ek[7] = t3;
+
+    t2 = _mm_aeskeygenassist_si128(t3, 0x08);
+    aes_256_assist1(&t1, &t2);
+    ek[8] = t1;
+    aes_256_assist2(&t1, &t3);
+    ek[9] = t3;
+
+    t2 = _mm_aeskeygenassist_si128(t3, 0x10);
+    aes_256_assist1(&t1, &t2);
+    ek[10] = t1;
+}
+
+/**
+ * @brief a "pseudo" round of AES (similar to but slightly different from normal AES encryption)
+ *
+ * To fill its 2MB scratch buffer, CryptoNight uses a nonstandard implementation
+ * of AES encryption:  It applies 10 rounds of the basic AES encryption operation
+ * to an input 128 bit chunk of data <in>.  Unlike normal AES, however, this is
+ * all it does;  it does not perform the initial AddRoundKey step (this is done
+ * in subsequent steps by aesenc_si128), and it does not use the simpler final round.
+ * Hence, this is a "pseudo" round - though the function actually implements 10 rounds together.
+ *
+ * Note that unlike aesb_pseudo_round, this function works on multiple data chunks.
+ *
+ * @param in a pointer to nblocks * 128 bits of data to be encrypted
+ * @param out a pointer to an nblocks * 128 bit buffer where the output will be stored
+ * @param expandedKey the expanded AES key
+ * @param nblocks the number of 128 blocks of data to be encrypted
+ */
+
+STATIC INLINE void aes_pseudo_round(const uint8_t *in, uint8_t *out,
+                                    const uint8_t *expandedKey, int nblocks)
+{
+    __m128i *k = R128(expandedKey);
+    __m128i d;
+    int i;
+
+    for(i = 0; i < nblocks; i++)
+    {
+        d = _mm_loadu_si128(R128(in + i * AES_BLOCK_SIZE));
+        d = _mm_aesenc_si128(d, *R128(&k[0]));
+        d = _mm_aesenc_si128(d, *R128(&k[1]));
+        d = _mm_aesenc_si128(d, *R128(&k[2]));
+        d = _mm_aesenc_si128(d, *R128(&k[3]));
+        d = _mm_aesenc_si128(d, *R128(&k[4]));
+        d = _mm_aesenc_si128(d, *R128(&k[5]));
+        d = _mm_aesenc_si128(d, *R128(&k[6]));
+        d = _mm_aesenc_si128(d, *R128(&k[7]));
+        d = _mm_aesenc_si128(d, *R128(&k[8]));
+        d = _mm_aesenc_si128(d, *R128(&k[9]));
+        _mm_storeu_si128((R128(out + i * AES_BLOCK_SIZE)), d);
+    }
+}
+
+/**
+ * @brief aes_pseudo_round that loads data from *in and xors it with *xor first
+ *
+ * This function performs the same operations as aes_pseudo_round, but before
+ * performing the encryption of each 128 bit block from <in>, it xors
+ * it with the corresponding block from <xor>.
+ *
+ * @param in a pointer to nblocks * 128 bits of data to be encrypted
+ * @param out a pointer to an nblocks * 128 bit buffer where the output will be stored
+ * @param expandedKey the expanded AES key
+ * @param xor a pointer to an nblocks * 128 bit buffer that is xored into in before encryption (in is left unmodified)
+ * @param nblocks the number of 128 blocks of data to be encrypted
+ */
+
+STATIC INLINE void aes_pseudo_round_xor(const uint8_t *in, uint8_t *out,
+                                        const uint8_t *expandedKey, const uint8_t *xor, int nblocks)
+{
+    __m128i *k = R128(expandedKey);
+    __m128i *x = R128(xor);
+    __m128i d;
+    int i;
+
+    for(i = 0; i < nblocks; i++)
+    {
+        d = _mm_loadu_si128(R128(in + i * AES_BLOCK_SIZE));
+        d = _mm_xor_si128(d, *R128(x++));
+        d = _mm_aesenc_si128(d, *R128(&k[0]));
+        d = _mm_aesenc_si128(d, *R128(&k[1]));
+        d = _mm_aesenc_si128(d, *R128(&k[2]));
+        d = _mm_aesenc_si128(d, *R128(&k[3]));
+        d = _mm_aesenc_si128(d, *R128(&k[4]));
+        d = _mm_aesenc_si128(d, *R128(&k[5]));
+        d = _mm_aesenc_si128(d, *R128(&k[6]));
+        d = _mm_aesenc_si128(d, *R128(&k[7]));
+        d = _mm_aesenc_si128(d, *R128(&k[8]));
+        d = _mm_aesenc_si128(d, *R128(&k[9]));
+        _mm_storeu_si128((R128(out + i * AES_BLOCK_SIZE)), d);
+    }
+}
+
+#if defined(_MSC_VER) || defined(__MINGW32__)
+BOOL SetLockPagesPrivilege(HANDLE hProcess, BOOL bEnable)
+{
+    struct
+    {
+        DWORD count;
+        LUID_AND_ATTRIBUTES privilege[1];
+    } info;
+
+    HANDLE token;
+    if(!OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES, &token))
+        return FALSE;
+
+    info.count = 1;
+    info.privilege[0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0;
+
+    if(!LookupPrivilegeValue(NULL, SE_LOCK_MEMORY_NAME, &(info.privilege[0].Luid)))
+        return FALSE;
+
+    if(!AdjustTokenPrivileges(token, FALSE, (PTOKEN_PRIVILEGES) &info, 0, NULL, NULL))
+        return FALSE;
+
+    if (GetLastError() != ERROR_SUCCESS)
+        return FALSE;
+
+    CloseHandle(token);
+
+    return TRUE;
+
+}
+#endif
+
+/**
+ * @brief allocate the 2MB scratch buffer using OS support for huge pages, if available
+ *
+ * This function tries to allocate the 2MB scratch buffer using a single
+ * 2MB "huge page" (instead of the usual 4KB page sizes) to reduce TLB misses
+ * during the random accesses to the scratch buffer.  This is one of the
+ * important speed optimizations needed to make CryptoNight faster.
+ *
+ * No parameters.  Updates a thread-local pointer, hp_state, to point to
+ * the allocated buffer.
+ */
+
+void slow_hash_allocate_state(void)
+{
+    if(hp_state != NULL)
+        return;
+
+#if defined(_MSC_VER) || defined(__MINGW32__)
+    SetLockPagesPrivilege(GetCurrentProcess(), TRUE);
+    hp_state = (uint8_t *) VirtualAlloc(hp_state, MEMORY, MEM_LARGE_PAGES |
+                                        MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+#else
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \
+  defined(__DragonFly__)
+    hp_state = mmap(0, MEMORY, PROT_READ | PROT_WRITE,
+                    MAP_PRIVATE | MAP_ANON, 0, 0);
+#else
+    hp_state = mmap(0, MEMORY, PROT_READ | PROT_WRITE,
+                    MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB, 0, 0);
+#endif
+    if(hp_state == MAP_FAILED)
+        hp_state = NULL;
+#endif
+    hp_allocated = 1;
+    if(hp_state == NULL)
+    {
+        hp_allocated = 0;
+        hp_state = (uint8_t *) malloc(MEMORY);
+    }
+}
+
+/**
+ *@brief frees the state allocated by slow_hash_allocate_state
+ */
+
+void slow_hash_free_state(void)
+{
+    if(hp_state == NULL)
+        return;
+
+    if(!hp_allocated)
+        free(hp_state);
+    else
+    {
+#if defined(_MSC_VER) || defined(__MINGW32__)
+        VirtualFree(hp_state, MEMORY, MEM_RELEASE);
+#else
+        munmap(hp_state, MEMORY);
+#endif
+    }
+
+    hp_state = NULL;
+    hp_allocated = 0;
+}
+
+/**
+ * @brief the hash function implementing CryptoNight, used for the Monero proof-of-work
+ *
+ * Computes the hash of <data> (which consists of <length> bytes), returning the
+ * hash in <hash>.  The CryptoNight hash operates by first using Keccak 1600,
+ * the 1600 bit variant of the Keccak hash used in SHA-3, to create a 200 byte
+ * buffer of pseudorandom data by hashing the supplied data.  It then uses this
+ * random data to fill a large 2MB buffer with pseudorandom data by iteratively
+ * encrypting it using 10 rounds of AES per entry.  After this initialization,
+ * it executes 524,288 rounds of mixing through the random 2MB buffer using
+ * AES (typically provided in hardware on modern CPUs) and a 64 bit multiply.
+ * Finally, it re-mixes this large buffer back into
+ * the 200 byte "text" buffer, and then hashes this buffer using one of four
+ * pseudorandomly selected hash functions (Blake, Groestl, JH, or Skein)
+ * to populate the output.
+ *
+ * The 2MB buffer and choice of functions for mixing are designed to make the
+ * algorithm "CPU-friendly" (and thus, reduce the advantage of GPU, FPGA,
+ * or ASIC-based implementations):  the functions used are fast on modern
+ * CPUs, and the 2MB size matches the typical amount of L3 cache available per
+ * core on 2013-era CPUs.  When available, this implementation will use hardware
+ * AES support on x86 CPUs.
+ *
+ * A diagram of the inner loop of this function can be found at
+ * http://www.cs.cmu.edu/~dga/crypto/xmr/cryptonight.png
+ *
+ * @param data the data to hash
+ * @param length the length in bytes of the data
+ * @param hash a pointer to a buffer in which the final 256 bit hash will be stored
+ */
+
+void cn_slow_hash(const void *data, size_t length, char *hash)
+{
+    RDATA_ALIGN16 uint8_t expandedKey[240];  /* These buffers are aligned to use later with SSE functions */
+
+    uint8_t text[INIT_SIZE_BYTE];
+    RDATA_ALIGN16 uint64_t a[2];
+    RDATA_ALIGN16 uint64_t b[2];
+    RDATA_ALIGN16 uint64_t c[2];
+    union cn_slow_hash_state state;
+    __m128i _a, _b, _c;
+    uint64_t hi, lo;
+
+    size_t i, j;
+    uint64_t *p = NULL;
+    oaes_ctx *aes_ctx = NULL;
+    int useAes = !force_software_aes() && check_aes_hw();
+
+    static void (*const extra_hashes[4])(const void *, size_t, char *) =
+    {
+        hash_extra_blake, hash_extra_groestl, hash_extra_jh, hash_extra_skein
+    };
+
+    // this isn't supposed to happen, but guard against it for now.
+    if(hp_state == NULL)
+        slow_hash_allocate_state();
+
+    /* CryptoNight Step 1:  Use Keccak1600 to initialize the 'state' (and 'text') buffers from the data. */
+
+    hash_process(&state.hs, data, length);
+    memcpy(text, state.init, INIT_SIZE_BYTE);
+
+    /* CryptoNight Step 2:  Iteratively encrypt the results from Keccak to fill
+     * the 2MB large random access buffer.
+     */
+
+    if(useAes)
+    {
+        aes_expand_key(state.hs.b, expandedKey);
+        for(i = 0; i < MEMORY / INIT_SIZE_BYTE; i++)
+        {
+            aes_pseudo_round(text, text, expandedKey, INIT_SIZE_BLK);
+            memcpy(&hp_state[i * INIT_SIZE_BYTE], text, INIT_SIZE_BYTE);
+        }
+    }
+    else
+    {
+        aes_ctx = (oaes_ctx *) oaes_alloc();
+        oaes_key_import_data(aes_ctx, state.hs.b, AES_KEY_SIZE);
+        for(i = 0; i < MEMORY / INIT_SIZE_BYTE; i++)
+        {
+            for(j = 0; j < INIT_SIZE_BLK; j++)
+                aesb_pseudo_round(&text[AES_BLOCK_SIZE * j], &text[AES_BLOCK_SIZE * j], aes_ctx->key->exp_data);
+
+            memcpy(&hp_state[i * INIT_SIZE_BYTE], text, INIT_SIZE_BYTE);
+        }
+    }
+
+    U64(a)[0] = U64(&state.k[0])[0] ^ U64(&state.k[32])[0];
+    U64(a)[1] = U64(&state.k[0])[1] ^ U64(&state.k[32])[1];
+    U64(b)[0] = U64(&state.k[16])[0] ^ U64(&state.k[48])[0];
+    U64(b)[1] = U64(&state.k[16])[1] ^ U64(&state.k[48])[1];
+
+    /* CryptoNight Step 3:  Bounce randomly 1,048,576 times (1<<20) through the mixing buffer,
+     * using 524,288 iterations of the following mixing function.  Each execution
+     * performs two reads and writes from the mixing buffer.
+     */
+
+    _b = _mm_load_si128(R128(b));
+    // Two independent versions, one with AES, one without, to ensure that
+    // the useAes test is only performed once, not every iteration.
+    if(useAes)
+    {
+        for(i = 0; i < ITER / 2; i++)
+        {
+            pre_aes();
+            _c = _mm_aesenc_si128(_c, _a);
+            post_aes();
+        }
+    }
+    else
+    {
+        for(i = 0; i < ITER / 2; i++)
+        {
+            pre_aes();
+            aesb_single_round((uint8_t *) &_c, (uint8_t *) &_c, (uint8_t *) &_a);
+            post_aes();
+        }
+    }
+
+    /* CryptoNight Step 4:  Sequentially pass through the mixing buffer and use 10 rounds
+     * of AES encryption to mix the random data back into the 'text' buffer.  'text'
+     * was originally created with the output of Keccak1600. */
+
+    memcpy(text, state.init, INIT_SIZE_BYTE);
+    if(useAes)
+    {
+        aes_expand_key(&state.hs.b[32], expandedKey);
+        for(i = 0; i < MEMORY / INIT_SIZE_BYTE; i++)
+        {
+            // add the xor to the pseudo round
+            aes_pseudo_round_xor(text, text, expandedKey, &hp_state[i * INIT_SIZE_BYTE], INIT_SIZE_BLK);
+        }
+    }
+    else
+    {
+        oaes_key_import_data(aes_ctx, &state.hs.b[32], AES_KEY_SIZE);
+        for(i = 0; i < MEMORY / INIT_SIZE_BYTE; i++)
+        {
+            for(j = 0; j < INIT_SIZE_BLK; j++)
+            {
+                xor_blocks(&text[j * AES_BLOCK_SIZE], &hp_state[i * INIT_SIZE_BYTE + j * AES_BLOCK_SIZE]);
+                aesb_pseudo_round(&text[AES_BLOCK_SIZE * j], &text[AES_BLOCK_SIZE * j], aes_ctx->key->exp_data);
+            }
+        }
+        oaes_free((OAES_CTX **) &aes_ctx);
+    }
+
+    /* CryptoNight Step 5:  Apply Keccak to the state again, and then
+     * use the resulting data to select which of four finalizer
+     * hash functions to apply to the data (Blake, Groestl, JH, or Skein).
+     * Use this hash to squeeze the state array down
+     * to the final 256 bit hash output.
+     */
+
+    memcpy(state.init, text, INIT_SIZE_BYTE);
+    hash_permutation(&state.hs);
+    extra_hashes[state.hs.b[0] & 3](&state, 200, hash);
+}
+
+#elif !defined NO_AES && (defined(__arm__) || defined(__aarch64__))
+void slow_hash_allocate_state(void)
+{
+  // Do nothing, this is just to maintain compatibility with the upgraded slow-hash.c
+  return;
+}
+
+void slow_hash_free_state(void)
+{
+  // As above
+  return;
+}
+
+#if defined(__GNUC__)
+#define RDATA_ALIGN16 __attribute__ ((aligned(16)))
+#define STATIC static
+#define INLINE inline
+#else
+#define RDATA_ALIGN16
+#define STATIC static
+#define INLINE
+#endif
+
+#define U64(x) ((uint64_t *) (x))
+
+#pragma pack(push, 1)
+union cn_slow_hash_state
+{
+    union hash_state hs;
+    struct
+    {
+        uint8_t k[64];
+        uint8_t init[INIT_SIZE_BYTE];
+    };
+};
+#pragma pack(pop)
+
+#if defined(__aarch64__) && defined(__ARM_FEATURE_CRYPTO)
+
+/* ARMv8-A optimized with NEON and AES instructions.
+ * Copied from the x86-64 AES-NI implementation. It has much the same
+ * characteristics as x86-64: there's no 64x64=128 multiplier for vectors,
+ * and moving between vector and regular registers stalls the pipeline.
+ */
+#include <arm_neon.h>
+
+#define TOTALBLOCKS (MEMORY / AES_BLOCK_SIZE)
+
+#define state_index(x) (((*((uint64_t *)x) >> 4) & (TOTALBLOCKS - 1)) << 4)
+#define __mul() __asm__("mul %0, %1, %2\n\t" : "=r"(lo) : "r"(c[0]), "r"(b[0]) ); \
+  __asm__("umulh %0, %1, %2\n\t" : "=r"(hi) : "r"(c[0]), "r"(b[0]) );
+
+#define pre_aes() \
+  j = state_index(a); \
+  _c = vld1q_u8(&hp_state[j]); \
+  _a = vld1q_u8((const uint8_t *)a); \
+
+#define post_aes() \
+  vst1q_u8((uint8_t *)c, _c); \
+  _b = veorq_u8(_b, _c); \
+  vst1q_u8(&hp_state[j], _b); \
+  j = state_index(c); \
+  p = U64(&hp_state[j]); \
+  b[0] = p[0]; b[1] = p[1]; \
+  __mul(); \
+  a[0] += hi; a[1] += lo; \
+  p = U64(&hp_state[j]); \
+  p[0] = a[0];  p[1] = a[1]; \
+  a[0] ^= b[0]; a[1] ^= b[1]; \
+  _b = _c; \
+
+
+/* Note: this was based on a standard 256bit key schedule but
+ * it's been shortened since Cryptonight doesn't use the full
+ * key schedule. Don't try to use this for vanilla AES.
+*/
+static void aes_expand_key(const uint8_t *key, uint8_t *expandedKey) {
+static const int rcon[] = {
+	0x01,0x01,0x01,0x01,
+	0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d,	// rotate-n-splat
+	0x1b,0x1b,0x1b,0x1b };
+__asm__(
+"	eor	v0.16b,v0.16b,v0.16b\n"
+"	ld1	{v3.16b},[%0],#16\n"
+"	ld1	{v1.4s,v2.4s},[%2],#32\n"
+"	ld1	{v4.16b},[%0]\n"
+"	mov	w2,#5\n"
+"	st1	{v3.4s},[%1],#16\n"
+"\n"
+"1:\n"
+"	tbl	v6.16b,{v4.16b},v2.16b\n"
+"	ext	v5.16b,v0.16b,v3.16b,#12\n"
+"	st1	{v4.4s},[%1],#16\n"
+"	aese	v6.16b,v0.16b\n"
+"	subs	w2,w2,#1\n"
+"\n"
+"	eor	v3.16b,v3.16b,v5.16b\n"
+"	ext	v5.16b,v0.16b,v5.16b,#12\n"
+"	eor	v3.16b,v3.16b,v5.16b\n"
+"	ext	v5.16b,v0.16b,v5.16b,#12\n"
+"	eor	v6.16b,v6.16b,v1.16b\n"
+"	eor	v3.16b,v3.16b,v5.16b\n"
+"	shl	v1.16b,v1.16b,#1\n"
+"	eor	v3.16b,v3.16b,v6.16b\n"
+"	st1	{v3.4s},[%1],#16\n"
+"	b.eq	2f\n"
+"\n"
+"	dup	v6.4s,v3.s[3]		// just splat\n"
+"	ext	v5.16b,v0.16b,v4.16b,#12\n"
+"	aese	v6.16b,v0.16b\n"
+"\n"
+"	eor	v4.16b,v4.16b,v5.16b\n"
+"	ext	v5.16b,v0.16b,v5.16b,#12\n"
+"	eor	v4.16b,v4.16b,v5.16b\n"
+"	ext	v5.16b,v0.16b,v5.16b,#12\n"
+"	eor	v4.16b,v4.16b,v5.16b\n"
+"\n"
+"	eor	v4.16b,v4.16b,v6.16b\n"
+"	b	1b\n"
+"\n"
+"2:\n" : : "r"(key), "r"(expandedKey), "r"(rcon));
+}
+
+/* An ordinary AES round is a sequence of SubBytes, ShiftRows, MixColumns, AddRoundKey. There
+ * is also an InitialRound which consists solely of AddRoundKey. The ARM instructions slice
+ * this sequence differently; the aese instruction performs AddRoundKey, SubBytes, ShiftRows.
+ * The aesmc instruction does the MixColumns. Since the aese instruction moves the AddRoundKey
+ * up front, and Cryptonight's hash skips the InitialRound step, we have to kludge it here by
+ * feeding in a vector of zeros for our first step. Also we have to do our own Xor explicitly
+ * at the last step, to provide the AddRoundKey that the ARM instructions omit.
+ */
+STATIC INLINE void aes_pseudo_round(const uint8_t *in, uint8_t *out, const uint8_t *expandedKey, int nblocks)
+{
+	const uint8x16_t *k = (const uint8x16_t *)expandedKey, zero = {0};
+	uint8x16_t tmp;
+	int i;
+
+	for (i=0; i<nblocks; i++)
+	{
+		uint8x16_t tmp = vld1q_u8(in + i * AES_BLOCK_SIZE);
+		tmp = vaeseq_u8(tmp, zero);
+		tmp = vaesmcq_u8(tmp);
+		tmp = vaeseq_u8(tmp, k[0]);
+		tmp = vaesmcq_u8(tmp);
+		tmp = vaeseq_u8(tmp, k[1]);
+		tmp = vaesmcq_u8(tmp);
+		tmp = vaeseq_u8(tmp, k[2]);
+		tmp = vaesmcq_u8(tmp);
+		tmp = vaeseq_u8(tmp, k[3]);
+		tmp = vaesmcq_u8(tmp);
+		tmp = vaeseq_u8(tmp, k[4]);
+		tmp = vaesmcq_u8(tmp);
+		tmp = vaeseq_u8(tmp, k[5]);
+		tmp = vaesmcq_u8(tmp);
+		tmp = vaeseq_u8(tmp, k[6]);
+		tmp = vaesmcq_u8(tmp);
+		tmp = vaeseq_u8(tmp, k[7]);
+		tmp = vaesmcq_u8(tmp);
+		tmp = vaeseq_u8(tmp, k[8]);
+		tmp = vaesmcq_u8(tmp);
+		tmp = veorq_u8(tmp,  k[9]);
+		vst1q_u8(out + i * AES_BLOCK_SIZE, tmp);
+	}
+}
+
+STATIC INLINE void aes_pseudo_round_xor(const uint8_t *in, uint8_t *out, const uint8_t *expandedKey, const uint8_t *xor, int nblocks)
+{
+	const uint8x16_t *k = (const uint8x16_t *)expandedKey;
+	const uint8x16_t *x = (const uint8x16_t *)xor;
+	uint8x16_t tmp;
+	int i;
+
+	for (i=0; i<nblocks; i++)
+	{
+		uint8x16_t tmp = vld1q_u8(in + i * AES_BLOCK_SIZE);
+		tmp = vaeseq_u8(tmp, x[i]);
+		tmp = vaesmcq_u8(tmp);
+		tmp = vaeseq_u8(tmp, k[0]);
+		tmp = vaesmcq_u8(tmp);
+		tmp = vaeseq_u8(tmp, k[1]);
+		tmp = vaesmcq_u8(tmp);
+		tmp = vaeseq_u8(tmp, k[2]);
+		tmp = vaesmcq_u8(tmp);
+		tmp = vaeseq_u8(tmp, k[3]);
+		tmp = vaesmcq_u8(tmp);
+		tmp = vaeseq_u8(tmp, k[4]);
+		tmp = vaesmcq_u8(tmp);
+		tmp = vaeseq_u8(tmp, k[5]);
+		tmp = vaesmcq_u8(tmp);
+		tmp = vaeseq_u8(tmp, k[6]);
+		tmp = vaesmcq_u8(tmp);
+		tmp = vaeseq_u8(tmp, k[7]);
+		tmp = vaesmcq_u8(tmp);
+		tmp = vaeseq_u8(tmp, k[8]);
+		tmp = vaesmcq_u8(tmp);
+		tmp = veorq_u8(tmp,  k[9]);
+		vst1q_u8(out + i * AES_BLOCK_SIZE, tmp);
+	}
+}
+
+void cn_slow_hash(const void *data, size_t length, char *hash)
+{
+    RDATA_ALIGN16 uint8_t expandedKey[240];
+    RDATA_ALIGN16 uint8_t hp_state[MEMORY];
+
+    uint8_t text[INIT_SIZE_BYTE];
+    RDATA_ALIGN16 uint64_t a[2];
+    RDATA_ALIGN16 uint64_t b[2];
+    RDATA_ALIGN16 uint64_t c[2];
+    union cn_slow_hash_state state;
+    uint8x16_t _a, _b, _c, zero = {0};
+    uint64_t hi, lo;
+
+    size_t i, j;
+    uint64_t *p = NULL;
+
+    static void (*const extra_hashes[4])(const void *, size_t, char *) =
+    {
+        hash_extra_blake, hash_extra_groestl, hash_extra_jh, hash_extra_skein
+    };
+
+    /* CryptoNight Step 1:  Use Keccak1600 to initialize the 'state' (and 'text') buffers from the data. */
+
+    hash_process(&state.hs, data, length);
+    memcpy(text, state.init, INIT_SIZE_BYTE);
+
+    /* CryptoNight Step 2:  Iteratively encrypt the results from Keccak to fill
+     * the 2MB large random access buffer.
+     */
+
+    aes_expand_key(state.hs.b, expandedKey);
+    for(i = 0; i < MEMORY / INIT_SIZE_BYTE; i++)
+    {
+        aes_pseudo_round(text, text, expandedKey, INIT_SIZE_BLK);
+        memcpy(&hp_state[i * INIT_SIZE_BYTE], text, INIT_SIZE_BYTE);
+    }
+
+    U64(a)[0] = U64(&state.k[0])[0] ^ U64(&state.k[32])[0];
+    U64(a)[1] = U64(&state.k[0])[1] ^ U64(&state.k[32])[1];
+    U64(b)[0] = U64(&state.k[16])[0] ^ U64(&state.k[48])[0];
+    U64(b)[1] = U64(&state.k[16])[1] ^ U64(&state.k[48])[1];
+
+    /* CryptoNight Step 3:  Bounce randomly 1,048,576 times (1<<20) through the mixing buffer,
+     * using 524,288 iterations of the following mixing function.  Each execution
+     * performs two reads and writes from the mixing buffer.
+     */
+
+    _b = vld1q_u8((const uint8_t *)b);
+
+
+    for(i = 0; i < ITER / 2; i++)
+    {
+        pre_aes();
+        _c = vaeseq_u8(_c, zero);
+        _c = vaesmcq_u8(_c);
+        _c = veorq_u8(_c, _a);
+        post_aes();
+    }
+
+    /* CryptoNight Step 4:  Sequentially pass through the mixing buffer and use 10 rounds
+     * of AES encryption to mix the random data back into the 'text' buffer.  'text'
+     * was originally created with the output of Keccak1600. */
+
+    memcpy(text, state.init, INIT_SIZE_BYTE);
+
+    aes_expand_key(&state.hs.b[32], expandedKey);
+    for(i = 0; i < MEMORY / INIT_SIZE_BYTE; i++)
+    {
+        // add the xor to the pseudo round
+        aes_pseudo_round_xor(text, text, expandedKey, &hp_state[i * INIT_SIZE_BYTE], INIT_SIZE_BLK);
+    }
+
+    /* CryptoNight Step 5:  Apply Keccak to the state again, and then
+     * use the resulting data to select which of four finalizer
+     * hash functions to apply to the data (Blake, Groestl, JH, or Skein).
+     * Use this hash to squeeze the state array down
+     * to the final 256 bit hash output.
+     */
+
+    memcpy(state.init, text, INIT_SIZE_BYTE);
+    hash_permutation(&state.hs);
+    extra_hashes[state.hs.b[0] & 3](&state, 200, hash);
+}
+#else /* aarch64 && crypto */
+
+// ND: Some minor optimizations for ARMv7 (raspberrry pi 2), effect seems to be ~40-50% faster.
+//     Needs more work.
+
+#ifdef NO_OPTIMIZED_MULTIPLY_ON_ARM
+/* The asm corresponds to this C code */
+#define SHORT uint32_t
+#define LONG uint64_t
+
+void mul(const uint8_t *ca, const uint8_t *cb, uint8_t *cres) {
+  const SHORT *aa = (SHORT *)ca;
+  const SHORT *bb = (SHORT *)cb;
+  SHORT *res = (SHORT *)cres;
+  union {
+    SHORT tmp[8];
+    LONG ltmp[4];
+  } t;
+  LONG A = aa[1];
+  LONG a = aa[0];
+  LONG B = bb[1];
+  LONG b = bb[0];
+
+  // Aa * Bb = ab + aB_ + Ab_ + AB__
+  t.ltmp[0] = a * b;
+  t.ltmp[1] = a * B;
+  t.ltmp[2] = A * b;
+  t.ltmp[3] = A * B;
+
+  res[2] = t.tmp[0];
+  t.ltmp[1] += t.tmp[1];
+  t.ltmp[1] += t.tmp[4];
+  t.ltmp[3] += t.tmp[3];
+  t.ltmp[3] += t.tmp[5];
+  res[3] = t.tmp[2];
+  res[0] = t.tmp[6];
+  res[1] = t.tmp[7];
+}
+#else // !NO_OPTIMIZED_MULTIPLY_ON_ARM
+
+#ifdef __aarch64__ /* ARM64, no crypto */
+#define mul(a, b, c)	cn_mul128((const uint64_t *)a, (const uint64_t *)b, (uint64_t *)c)
+STATIC void cn_mul128(const uint64_t *a, const uint64_t *b, uint64_t *r)
+{
+  uint64_t lo, hi;
+  __asm__("mul %0, %1, %2\n\t" : "=r"(lo) : "r"(a[0]), "r"(b[0]) );
+  __asm__("umulh %0, %1, %2\n\t" : "=r"(hi) : "r"(a[0]), "r"(b[0]) );
+  r[0] = hi;
+  r[1] = lo;
+}
+#else /* ARM32 */
+#define mul(a, b, c)	cn_mul128((const uint32_t *)a, (const uint32_t *)b, (uint32_t *)c)
+STATIC void cn_mul128(const uint32_t *aa, const uint32_t *bb, uint32_t *r)
+{
+  uint32_t t0, t1, t2=0, t3=0;
+__asm__ __volatile__(
+  "umull %[t0], %[t1], %[a], %[b]\n\t"
+  "str   %[t0], %[ll]\n\t"
+
+  // accumulating with 0 can never overflow/carry
+  "eor   %[t0], %[t0]\n\t"
+  "umlal %[t1], %[t0], %[a], %[B]\n\t"
+
+  "umlal %[t1], %[t2], %[A], %[b]\n\t"
+  "str   %[t1], %[lh]\n\t"
+
+  "umlal %[t0], %[t3], %[A], %[B]\n\t"
+
+  // final add may have a carry
+  "adds  %[t0], %[t0], %[t2]\n\t"
+  "adc   %[t1], %[t3], #0\n\t"
+
+  "str   %[t0], %[hl]\n\t"
+  "str   %[t1], %[hh]\n\t"
+  : [t0]"=&r"(t0), [t1]"=&r"(t1), [t2]"+r"(t2), [t3]"+r"(t3), [hl]"=m"(r[0]), [hh]"=m"(r[1]), [ll]"=m"(r[2]), [lh]"=m"(r[3])
+  : [A]"r"(aa[1]), [a]"r"(aa[0]), [B]"r"(bb[1]), [b]"r"(bb[0])
+  : "cc");
+}
+#endif /* !aarch64 */
+#endif // NO_OPTIMIZED_MULTIPLY_ON_ARM
+
+STATIC INLINE void sum_half_blocks(uint8_t* a, const uint8_t* b)
+{
+  uint64_t a0, a1, b0, b1;
+  a0 = U64(a)[0];
+  a1 = U64(a)[1];
+  b0 = U64(b)[0];
+  b1 = U64(b)[1];
+  a0 += b0;
+  a1 += b1;
+  U64(a)[0] = a0;
+  U64(a)[1] = a1;
+}
+
+STATIC INLINE void swap_blocks(uint8_t *a, uint8_t *b)
+{
+  uint64_t t[2];
+  U64(t)[0] = U64(a)[0];
+  U64(t)[1] = U64(a)[1];
+  U64(a)[0] = U64(b)[0];
+  U64(a)[1] = U64(b)[1];
+  U64(b)[0] = U64(t)[0];
+  U64(b)[1] = U64(t)[1];
+}
+
+STATIC INLINE void xor_blocks(uint8_t* a, const uint8_t* b)
+{
+  U64(a)[0] ^= U64(b)[0];
+  U64(a)[1] ^= U64(b)[1];
+}
+
+void cn_slow_hash(const void *data, size_t length, char *hash)
+{
+    uint8_t text[INIT_SIZE_BYTE];
+    uint8_t a[AES_BLOCK_SIZE];
+    uint8_t b[AES_BLOCK_SIZE];
+    uint8_t d[AES_BLOCK_SIZE];
+    uint8_t aes_key[AES_KEY_SIZE];
+    RDATA_ALIGN16 uint8_t expandedKey[256];
+
+    union cn_slow_hash_state state;
+
+    size_t i, j;
+    uint8_t *p = NULL;
+    oaes_ctx *aes_ctx;
+    static void (*const extra_hashes[4])(const void *, size_t, char *) =
+    {
+        hash_extra_blake, hash_extra_groestl, hash_extra_jh, hash_extra_skein
+    };
+
+#ifndef FORCE_USE_HEAP
+    uint8_t long_state[MEMORY];
+#else
+    uint8_t *long_state = NULL;
+    long_state = (uint8_t *)malloc(MEMORY);
+#endif
+
+    hash_process(&state.hs, data, length);
+    memcpy(text, state.init, INIT_SIZE_BYTE);
+
+    aes_ctx = (oaes_ctx *) oaes_alloc();
+    oaes_key_import_data(aes_ctx, state.hs.b, AES_KEY_SIZE);
+
+    // use aligned data
+    memcpy(expandedKey, aes_ctx->key->exp_data, aes_ctx->key->exp_data_len);
+    for(i = 0; i < MEMORY / INIT_SIZE_BYTE; i++)
+    {
+        for(j = 0; j < INIT_SIZE_BLK; j++)
+            aesb_pseudo_round(&text[AES_BLOCK_SIZE * j], &text[AES_BLOCK_SIZE * j], expandedKey);
+        memcpy(&long_state[i * INIT_SIZE_BYTE], text, INIT_SIZE_BYTE);
+    }
+
+    U64(a)[0] = U64(&state.k[0])[0] ^ U64(&state.k[32])[0];
+    U64(a)[1] = U64(&state.k[0])[1] ^ U64(&state.k[32])[1];
+    U64(b)[0] = U64(&state.k[16])[0] ^ U64(&state.k[48])[0];
+    U64(b)[1] = U64(&state.k[16])[1] ^ U64(&state.k[48])[1];
+
+    for(i = 0; i < ITER / 2; i++)
+    {
+      #define MASK ((uint32_t)(((MEMORY / AES_BLOCK_SIZE) - 1) << 4))
+      #define state_index(x) ((*(uint32_t *) x) & MASK)
+
+      // Iteration 1
+      p = &long_state[state_index(a)];
+      aesb_single_round(p, p, a);
+
+      xor_blocks(b, p);
+      swap_blocks(b, p);
+      swap_blocks(a, b);
+
+      // Iteration 2
+      p = &long_state[state_index(a)];
+
+      mul(a, p, d);
+      sum_half_blocks(b, d);
+      swap_blocks(b, p);
+      xor_blocks(b, p);
+      swap_blocks(a, b);
+    }
+
+    memcpy(text, state.init, INIT_SIZE_BYTE);
+    oaes_key_import_data(aes_ctx, &state.hs.b[32], AES_KEY_SIZE);
+    memcpy(expandedKey, aes_ctx->key->exp_data, aes_ctx->key->exp_data_len);
+    for(i = 0; i < MEMORY / INIT_SIZE_BYTE; i++)
+    {
+        for(j = 0; j < INIT_SIZE_BLK; j++)
+        {
+            xor_blocks(&text[j * AES_BLOCK_SIZE], &long_state[i * INIT_SIZE_BYTE + j * AES_BLOCK_SIZE]);
+            aesb_pseudo_round(&text[AES_BLOCK_SIZE * j], &text[AES_BLOCK_SIZE * j], expandedKey);
+        }
+    }
+
+    oaes_free((OAES_CTX **) &aes_ctx);
+    memcpy(state.init, text, INIT_SIZE_BYTE);
+    hash_permutation(&state.hs);
+    extra_hashes[state.hs.b[0] & 3](&state, 200, hash);
+#ifdef FORCE_USE_HEAP
+    free(long_state);
+#endif
+}
+#endif /* !aarch64 || !crypto */
+
+#else
+// Portable implementation as a fallback
+
+void slow_hash_allocate_state(void)
+{
+  // Do nothing, this is just to maintain compatibility with the upgraded slow-hash.c
+  return;
+}
+
+void slow_hash_free_state(void)
+{
+  // As above
+  return;
+}
+
+static void (*const extra_hashes[4])(const void *, size_t, char *) = {
+  hash_extra_blake, hash_extra_groestl, hash_extra_jh, hash_extra_skein
+};
+
+extern int aesb_single_round(const uint8_t *in, uint8_t*out, const uint8_t *expandedKey);
+extern int aesb_pseudo_round(const uint8_t *in, uint8_t *out, const uint8_t *expandedKey);
+
+static size_t e2i(const uint8_t* a, size_t count) { return (*((uint64_t*)a) / AES_BLOCK_SIZE) & (count - 1); }
+
+static void mul(const uint8_t* a, const uint8_t* b, uint8_t* res) {
+  uint64_t a0, b0;
+  uint64_t hi, lo;
+
+  a0 = SWAP64LE(((uint64_t*)a)[0]);
+  b0 = SWAP64LE(((uint64_t*)b)[0]);
+  lo = mul128(a0, b0, &hi);
+  ((uint64_t*)res)[0] = SWAP64LE(hi);
+  ((uint64_t*)res)[1] = SWAP64LE(lo);
+}
+
+static void sum_half_blocks(uint8_t* a, const uint8_t* b) {
+  uint64_t a0, a1, b0, b1;
+
+  a0 = SWAP64LE(((uint64_t*)a)[0]);
+  a1 = SWAP64LE(((uint64_t*)a)[1]);
+  b0 = SWAP64LE(((uint64_t*)b)[0]);
+  b1 = SWAP64LE(((uint64_t*)b)[1]);
+  a0 += b0;
+  a1 += b1;
+  ((uint64_t*)a)[0] = SWAP64LE(a0);
+  ((uint64_t*)a)[1] = SWAP64LE(a1);
+}
+#define U64(x) ((uint64_t *) (x))
+
+static void copy_block(uint8_t* dst, const uint8_t* src) {
+  memcpy(dst, src, AES_BLOCK_SIZE);
+}
+
+static void swap_blocks(uint8_t *a, uint8_t *b){
+  uint64_t t[2];
+  U64(t)[0] = U64(a)[0];
+  U64(t)[1] = U64(a)[1];
+  U64(a)[0] = U64(b)[0];
+  U64(a)[1] = U64(b)[1];
+  U64(b)[0] = U64(t)[0];
+  U64(b)[1] = U64(t)[1];
+}
+
+static void xor_blocks(uint8_t* a, const uint8_t* b) {
+  size_t i;
+  for (i = 0; i < AES_BLOCK_SIZE; i++) {
+    a[i] ^= b[i];
+  }
+}
+
+#pragma pack(push, 1)
+union cn_slow_hash_state {
+  union hash_state hs;
+  struct {
+    uint8_t k[64];
+    uint8_t init[INIT_SIZE_BYTE];
+  };
+};
+#pragma pack(pop)
+
+void cn_slow_hash(const void *data, size_t length, char *hash) {
+  uint8_t long_state[MEMORY];
+  union cn_slow_hash_state state;
+  uint8_t text[INIT_SIZE_BYTE];
+  uint8_t a[AES_BLOCK_SIZE];
+  uint8_t b[AES_BLOCK_SIZE];
+  uint8_t c[AES_BLOCK_SIZE];
+  uint8_t d[AES_BLOCK_SIZE];
+  size_t i, j;
+  uint8_t aes_key[AES_KEY_SIZE];
+  oaes_ctx *aes_ctx;
+
+  hash_process(&state.hs, data, length);
+  memcpy(text, state.init, INIT_SIZE_BYTE);
+  memcpy(aes_key, state.hs.b, AES_KEY_SIZE);
+  aes_ctx = (oaes_ctx *) oaes_alloc();
+
+  oaes_key_import_data(aes_ctx, aes_key, AES_KEY_SIZE);
+  for (i = 0; i < MEMORY / INIT_SIZE_BYTE; i++) {
+    for (j = 0; j < INIT_SIZE_BLK; j++) {
+      aesb_pseudo_round(&text[AES_BLOCK_SIZE * j], &text[AES_BLOCK_SIZE * j], aes_ctx->key->exp_data);
+    }
+    memcpy(&long_state[i * INIT_SIZE_BYTE], text, INIT_SIZE_BYTE);
+  }
+
+  for (i = 0; i < 16; i++) {
+    a[i] = state.k[     i] ^ state.k[32 + i];
+    b[i] = state.k[16 + i] ^ state.k[48 + i];
+  }
+
+  for (i = 0; i < ITER / 2; i++) {
+    /* Dependency chain: address -> read value ------+
+     * written value <-+ hard function (AES or MUL) <+
+     * next address  <-+
+     */
+    /* Iteration 1 */
+    j = e2i(a, MEMORY / AES_BLOCK_SIZE);
+    copy_block(c, &long_state[j * AES_BLOCK_SIZE]);
+    aesb_single_round(c, c, a);
+    xor_blocks(b, c);
+    swap_blocks(b, c);
+    copy_block(&long_state[j * AES_BLOCK_SIZE], c);
+    assert(j == e2i(a, MEMORY / AES_BLOCK_SIZE));
+    swap_blocks(a, b);
+    /* Iteration 2 */
+    j = e2i(a, MEMORY / AES_BLOCK_SIZE);
+    copy_block(c, &long_state[j * AES_BLOCK_SIZE]);
+    mul(a, c, d);
+    sum_half_blocks(b, d);
+    swap_blocks(b, c);
+    xor_blocks(b, c);
+    copy_block(&long_state[j * AES_BLOCK_SIZE], c);
+    assert(j == e2i(a, MEMORY / AES_BLOCK_SIZE));
+    swap_blocks(a, b);
+  }
+
+  memcpy(text, state.init, INIT_SIZE_BYTE);
+  oaes_key_import_data(aes_ctx, &state.hs.b[32], AES_KEY_SIZE);
+  for (i = 0; i < MEMORY / INIT_SIZE_BYTE; i++) {
+    for (j = 0; j < INIT_SIZE_BLK; j++) {
+      xor_blocks(&text[j * AES_BLOCK_SIZE], &long_state[i * INIT_SIZE_BYTE + j * AES_BLOCK_SIZE]);
+      aesb_pseudo_round(&text[AES_BLOCK_SIZE * j], &text[AES_BLOCK_SIZE * j], aes_ctx->key->exp_data);
+    }
+  }
+  memcpy(state.init, text, INIT_SIZE_BYTE);
+  hash_permutation(&state.hs);
+  /*memcpy(hash, &state, 32);*/
+  extra_hashes[state.hs.b[0] & 3](&state, 200, hash);
+  oaes_free((OAES_CTX **) &aes_ctx);
+}
+
+#endif
diff --git a/crypt/monero_crypto/tree-hash.c b/crypt/monero_crypto/tree-hash.c
new file mode 100644
index 0000000000..eb98c31b78
--- /dev/null
+++ b/crypt/monero_crypto/tree-hash.c
@@ -0,0 +1,111 @@
+// 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
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "hash-ops.h"
+
+#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__)
+ #include <alloca.h>
+#else
+ #include <stdlib.h>
+#endif
+
+/*** 
+* Round to power of two, for count>=3 and for count being not too large (as reasonable for tree hash calculations)
+*/
+size_t tree_hash_cnt(size_t count) {
+	// This algo has some bad history but all we are doing is 1 << floor(log2(count))
+	// There are _many_ ways to do log2, for some reason the one selected was the most obscure one,
+	// and fixing it made it even more obscure.
+	//
+	// Iterative method implemented below aims for clarity over speed, if performance is needed
+	// then my advice is to use the BSR instruction on x86
+	//
+	// All the paranoid asserts have been removed since it is trivial to mathematically prove that
+	// the return will always be a power of 2.
+	// Problem space has been defined as 3 <= count <= 2^28. Of course quarter of a billion transactions
+	// is not a sane upper limit for a block, so there will be tighter limits in other parts of the code
+
+	assert( count >= 3 ); // cases for 0,1,2 are handled elsewhere
+	assert( count <= 0x10000000 ); // sanity limit to 2^28, MSB=1 will cause an inf loop
+
+	size_t pow = 2;
+	while(pow < count) pow <<= 1;
+	return pow >> 1;
+}
+
+void tree_hash(const char (*hashes)[HASH_SIZE], size_t count, char *root_hash) {
+// The blockchain block at height 202612 http://monerochain.info/block/bbd604d2ba11ba27935e006ed39c9bfdd99b76bf4a50654bc1e1e61217962698
+// contained 514 transactions, that triggered bad calculation of variable "cnt" in the original version of this function
+// as from CryptoNote code.
+//
+// This bug applies to all CN altcoins.
+//
+// Mathematical bug here was first published on 14:45:34 (GMT+2) 2014-09-04 by Rafal Freeman <rfree>
+// https://github.com/rfree2monero/bitmonero/commit/b417abfb7a297d09f1bbb6de29030f8de9952ac8
+// and soon also applied to CryptoNote (15:10 GMT+2), and BoolBerry used not fully correct work around:
+// the work around of sizeof(size_t)*8 or <<3 as used before in 2 coins and in BBL later was blocking
+// exploitation on normal platforms, how ever we strongly recommend the following fix because it removes
+// mistake in mathematical formula.
+
+  assert(count > 0);
+  if (count == 1) {
+    memcpy(root_hash, hashes, HASH_SIZE);
+  } else if (count == 2) {
+    cn_fast_hash(hashes, 2 * HASH_SIZE, root_hash);
+  } else {
+    size_t i, j;
+
+    size_t cnt = tree_hash_cnt( count );
+
+    char (*ints)[HASH_SIZE];
+    size_t ints_size = cnt * HASH_SIZE;
+    ints = alloca(ints_size); 	memset( ints , 0 , ints_size);  // allocate, and zero out as extra protection for using uninitialized mem
+
+    memcpy(ints, hashes, (2 * cnt - count) * HASH_SIZE);
+
+    for (i = 2 * cnt - count, j = 2 * cnt - count; j < cnt; i += 2, ++j) {
+      cn_fast_hash(hashes[i], 64, ints[j]);
+    }
+    assert(i == count);
+
+    while (cnt > 2) {
+      cnt >>= 1;
+      for (i = 0, j = 0; j < cnt; i += 2, ++j) {
+        cn_fast_hash(ints[i], 64, ints[j]);
+      }
+    }
+
+    cn_fast_hash(ints[0], 64, root_hash);
+  }
+}
-- 
GitLab