From c534f31fac6b728cca2bae4419def1587e9a4d6a Mon Sep 17 00:00:00 2001 From: Dmitriy Gerasimov <dm@cifercom.com> Date: Fri, 12 Jan 2018 15:32:23 +0700 Subject: [PATCH] [+] Monero crypto moved from libdap/crypto [+] HashFusion from brian.monahan@hpe.com (c) Copyright 2017 Hewlett Packard Enterprise Development LP [+] wrapper for hash functions moved also from libdap/crypto --- CMakeLists.txt | 18 +- dap_chain.c | 40 +- dap_chain.h | 16 +- dap_chain_block.h | 16 +- dap_chain_block_section.h | 2 +- dap_chain_common.h | 3 + dap_chain_tx.c | 42 + dap_chain_tx.h | 29 + dap_hash.c | 4 + dap_hash.h | 30 + dap_hash_fusion.c | 4 + dap_hash_fusion.h | 5 + dap_hash_keccak.c | 0 dap_hash_keccak.h | 10 + dap_hash_slow.c | 0 dap_hash_slow.h | 21 + hash_fusion/Makefile.old | 105 + hash_fusion/example/hmt.c | 973 +++++ hash_fusion/lib/alloc.c | 434 ++ hash_fusion/lib/alloc.h | 113 + hash_fusion/lib/arena.h | 104 + hash_fusion/lib/bytevector.c | 750 ++++ hash_fusion/lib/bytevector.h | 197 + hash_fusion/lib/debug.h | 54 + hash_fusion/lib/exptLib.c | 188 + hash_fusion/lib/exptLib.h | 77 + hash_fusion/lib/fragment.c | 323 ++ hash_fusion/lib/fragment.h | 142 + hash_fusion/lib/fragmentMap.c | 1218 ++++++ hash_fusion/lib/fragmentMap.h | 148 + hash_fusion/lib/hashFusion.c | 580 +++ hash_fusion/lib/hashFusion.h | 175 + hash_fusion/lib/hashlib.c | 719 ++++ hash_fusion/lib/hashlib.h | 185 + hash_fusion/lib/linearMap.c | 321 ++ hash_fusion/lib/linearMap.h | 75 + hash_fusion/lib/linkedList.c | 829 ++++ hash_fusion/lib/linkedList.h | 205 + hash_fusion/lib/matrix.c | 1689 ++++++++ hash_fusion/lib/matrix.h | 196 + hash_fusion/lib/merkleTree.c | 1189 ++++++ hash_fusion/lib/merkleTree.h | 135 + hash_fusion/lib/options.h | 43 + hash_fusion/lib/position.h | 39 + hash_fusion/lib/random.c | 141 + hash_fusion/lib/random.h | 80 + hash_fusion/lib/rbTree.c | 2185 ++++++++++ hash_fusion/lib/rbTree.h | 229 ++ hash_fusion/lib/stringbuffer.c | 179 + hash_fusion/lib/stringbuffer.h | 116 + hash_fusion/lib/testLib.c | 258 ++ hash_fusion/lib/testLib.h | 104 + hash_fusion/lib/utils.c | 567 +++ hash_fusion/lib/utils.h | 749 ++++ monero_crypto/CMakeLists.txt | 404 ++ monero_crypto/aesb.c | 185 + monero_crypto/blake256.c | 355 ++ monero_crypto/blake256.h | 73 + monero_crypto/chacha8.c | 170 + monero_crypto/chacha8.h | 79 + monero_crypto/common/int-util.h | 249 ++ monero_crypto/common/memwipe.c | 106 + monero_crypto/common/memwipe.h | 36 + monero_crypto/crypto-ops-data.c | 872 ++++ monero_crypto/crypto-ops.c | 3580 +++++++++++++++++ monero_crypto/crypto-ops.h | 156 + monero_crypto/crypto_ops_builder/Makefile | 10 + monero_crypto/crypto_ops_builder/README.md | 21 + monero_crypto/crypto_ops_builder/api.h | 2 + .../crypto_ops_builder/crypto-ops-data.c | 872 ++++ .../crypto_ops_builder/crypto-ops-old.c | 3008 ++++++++++++++ monero_crypto/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 + monero_crypto/crypto_ops_builder/ref10/api.h | 4 + monero_crypto/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 + monero_crypto/crypto_ops_builder/ref10/d.h | 1 + monero_crypto/crypto_ops_builder/ref10/d.py | 28 + monero_crypto/crypto_ops_builder/ref10/d2.h | 1 + monero_crypto/crypto_ops_builder/ref10/d2.py | 28 + .../crypto_ops_builder/ref10/description | 2 + .../crypto_ops_builder/ref10/designers | 5 + monero_crypto/crypto_ops_builder/ref10/fe.h | 56 + monero_crypto/crypto_ops_builder/ref10/fe_0.c | 19 + monero_crypto/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 + monero_crypto/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 + monero_crypto/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 + monero_crypto/crypto_ops_builder/ref10/q2h.sh | 4 + monero_crypto/crypto_ops_builder/ref10/sc.h | 15 + .../crypto_ops_builder/ref10/sc_muladd.c | 368 ++ .../crypto_ops_builder/ref10/sc_reduce.c | 275 ++ monero_crypto/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 + monero_crypto/generic-ops.h | 62 + monero_crypto/groestl.c | 360 ++ monero_crypto/groestl.h | 88 + monero_crypto/groestl_tables.h | 66 + monero_crypto/hash-extra-blake.c | 38 + monero_crypto/hash-extra-groestl.c | 38 + monero_crypto/hash-extra-jh.c | 42 + monero_crypto/hash-extra-skein.c | 40 + monero_crypto/hash-ops.h | 90 + monero_crypto/hash.c | 50 + monero_crypto/hash.h | 94 + monero_crypto/initializer.h | 63 + monero_crypto/jh.c | 367 ++ monero_crypto/jh.h | 21 + monero_crypto/keccak.c | 124 + monero_crypto/keccak.h | 26 + monero_crypto/oaes_config.h | 50 + monero_crypto/oaes_lib.c | 1500 +++++++ monero_crypto/oaes_lib.h | 215 + monero_crypto/random.c | 143 + monero_crypto/random.h | 35 + monero_crypto/skein.c | 2036 ++++++++++ monero_crypto/skein.h | 47 + monero_crypto/skein_port.h | 218 + monero_crypto/slow-hash.c | 1284 ++++++ monero_crypto/tree-hash.c | 111 + monero_crypto/warnings.h | 33 + 267 files changed, 47855 insertions(+), 13 deletions(-) create mode 100644 dap_hash.c create mode 100644 dap_hash.h create mode 100644 dap_hash_fusion.c create mode 100644 dap_hash_fusion.h create mode 100644 dap_hash_keccak.c create mode 100644 dap_hash_keccak.h create mode 100644 dap_hash_slow.c create mode 100644 dap_hash_slow.h create mode 100644 hash_fusion/Makefile.old create mode 100644 hash_fusion/example/hmt.c create mode 100644 hash_fusion/lib/alloc.c create mode 100644 hash_fusion/lib/alloc.h create mode 100644 hash_fusion/lib/arena.h create mode 100644 hash_fusion/lib/bytevector.c create mode 100644 hash_fusion/lib/bytevector.h create mode 100644 hash_fusion/lib/debug.h create mode 100644 hash_fusion/lib/exptLib.c create mode 100644 hash_fusion/lib/exptLib.h create mode 100644 hash_fusion/lib/fragment.c create mode 100644 hash_fusion/lib/fragment.h create mode 100644 hash_fusion/lib/fragmentMap.c create mode 100644 hash_fusion/lib/fragmentMap.h create mode 100644 hash_fusion/lib/hashFusion.c create mode 100644 hash_fusion/lib/hashFusion.h create mode 100644 hash_fusion/lib/hashlib.c create mode 100644 hash_fusion/lib/hashlib.h create mode 100644 hash_fusion/lib/linearMap.c create mode 100644 hash_fusion/lib/linearMap.h create mode 100644 hash_fusion/lib/linkedList.c create mode 100644 hash_fusion/lib/linkedList.h create mode 100644 hash_fusion/lib/matrix.c create mode 100644 hash_fusion/lib/matrix.h create mode 100644 hash_fusion/lib/merkleTree.c create mode 100644 hash_fusion/lib/merkleTree.h create mode 100644 hash_fusion/lib/options.h create mode 100644 hash_fusion/lib/position.h create mode 100644 hash_fusion/lib/random.c create mode 100644 hash_fusion/lib/random.h create mode 100644 hash_fusion/lib/rbTree.c create mode 100644 hash_fusion/lib/rbTree.h create mode 100644 hash_fusion/lib/stringbuffer.c create mode 100644 hash_fusion/lib/stringbuffer.h create mode 100644 hash_fusion/lib/testLib.c create mode 100644 hash_fusion/lib/testLib.h create mode 100644 hash_fusion/lib/utils.c create mode 100644 hash_fusion/lib/utils.h create mode 100644 monero_crypto/CMakeLists.txt create mode 100644 monero_crypto/aesb.c create mode 100644 monero_crypto/blake256.c create mode 100644 monero_crypto/blake256.h create mode 100644 monero_crypto/chacha8.c create mode 100644 monero_crypto/chacha8.h create mode 100644 monero_crypto/common/int-util.h create mode 100644 monero_crypto/common/memwipe.c create mode 100644 monero_crypto/common/memwipe.h create mode 100644 monero_crypto/crypto-ops-data.c create mode 100644 monero_crypto/crypto-ops.c create mode 100644 monero_crypto/crypto-ops.h create mode 100755 monero_crypto/crypto_ops_builder/Makefile create mode 100644 monero_crypto/crypto_ops_builder/README.md create mode 100755 monero_crypto/crypto_ops_builder/api.h create mode 100644 monero_crypto/crypto_ops_builder/crypto-ops-data.c create mode 100644 monero_crypto/crypto_ops_builder/crypto-ops-old.c create mode 100644 monero_crypto/crypto_ops_builder/crypto-ops.h create mode 100755 monero_crypto/crypto_ops_builder/crypto_int32.h create mode 100755 monero_crypto/crypto_ops_builder/crypto_sign.h create mode 100755 monero_crypto/crypto_ops_builder/crypto_uint32.h create mode 100755 monero_crypto/crypto_ops_builder/crypto_verify_32.h create mode 100644 monero_crypto/crypto_ops_builder/ietf.txt create mode 100644 monero_crypto/crypto_ops_builder/include/Makefile.am create mode 100644 monero_crypto/crypto_ops_builder/include/libsodium_LICENSE create mode 100644 monero_crypto/crypto_ops_builder/include/sodium.h create mode 100644 monero_crypto/crypto_ops_builder/include/sodium/crypto_int32.h create mode 100644 monero_crypto/crypto_ops_builder/include/sodium/crypto_int64.h create mode 100644 monero_crypto/crypto_ops_builder/include/sodium/crypto_uint16.h create mode 100644 monero_crypto/crypto_ops_builder/include/sodium/crypto_uint32.h create mode 100644 monero_crypto/crypto_ops_builder/include/sodium/crypto_uint64.h create mode 100644 monero_crypto/crypto_ops_builder/include/sodium/crypto_uint8.h create mode 100644 monero_crypto/crypto_ops_builder/include/sodium/crypto_verify_32.h create mode 100644 monero_crypto/crypto_ops_builder/include/sodium/randombytes.h create mode 100755 monero_crypto/crypto_ops_builder/randombytes.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/Makefile create mode 100644 monero_crypto/crypto_ops_builder/ref10/api.h create mode 100644 monero_crypto/crypto_ops_builder/ref10/base.h create mode 100644 monero_crypto/crypto_ops_builder/ref10/base.py create mode 100644 monero_crypto/crypto_ops_builder/ref10/base2.h create mode 100644 monero_crypto/crypto_ops_builder/ref10/base2.py create mode 100644 monero_crypto/crypto_ops_builder/ref10/d.h create mode 100644 monero_crypto/crypto_ops_builder/ref10/d.py create mode 100644 monero_crypto/crypto_ops_builder/ref10/d2.h create mode 100644 monero_crypto/crypto_ops_builder/ref10/d2.py create mode 100644 monero_crypto/crypto_ops_builder/ref10/description create mode 100644 monero_crypto/crypto_ops_builder/ref10/designers create mode 100644 monero_crypto/crypto_ops_builder/ref10/fe.h create mode 100644 monero_crypto/crypto_ops_builder/ref10/fe_0.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/fe_1.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/fe_add.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/fe_cmov.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/fe_copy.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/fe_frombytes.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/fe_invert.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/fe_isnegative.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/fe_isnonzero.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/fe_mul.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/fe_neg.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/fe_pow22523.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/fe_sq.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/fe_sq2.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/fe_sub.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/fe_tobytes.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/ge.h create mode 100644 monero_crypto/crypto_ops_builder/ref10/ge_add.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/ge_add.h create mode 100644 monero_crypto/crypto_ops_builder/ref10/ge_add.q create mode 100644 monero_crypto/crypto_ops_builder/ref10/ge_double_scalarmult.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/ge_frombytes.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/ge_madd.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/ge_madd.h create mode 100644 monero_crypto/crypto_ops_builder/ref10/ge_madd.q create mode 100644 monero_crypto/crypto_ops_builder/ref10/ge_msub.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/ge_msub.h create mode 100644 monero_crypto/crypto_ops_builder/ref10/ge_msub.q create mode 100644 monero_crypto/crypto_ops_builder/ref10/ge_p1p1_to_p2.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/ge_p1p1_to_p3.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/ge_p2_0.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/ge_p2_dbl.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/ge_p2_dbl.h create mode 100644 monero_crypto/crypto_ops_builder/ref10/ge_p2_dbl.q create mode 100644 monero_crypto/crypto_ops_builder/ref10/ge_p3_0.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/ge_p3_dbl.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/ge_p3_to_cached.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/ge_p3_to_p2.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/ge_p3_tobytes.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/ge_precomp_0.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/ge_scalarmult_base.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/ge_sub.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/ge_sub.h create mode 100644 monero_crypto/crypto_ops_builder/ref10/ge_sub.q create mode 100644 monero_crypto/crypto_ops_builder/ref10/ge_tobytes.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/keypair.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/open.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/pow22523.h create mode 100644 monero_crypto/crypto_ops_builder/ref10/pow22523.q create mode 100644 monero_crypto/crypto_ops_builder/ref10/pow225521.h create mode 100644 monero_crypto/crypto_ops_builder/ref10/pow225521.q create mode 100644 monero_crypto/crypto_ops_builder/ref10/q2h.sh create mode 100644 monero_crypto/crypto_ops_builder/ref10/sc.h create mode 100644 monero_crypto/crypto_ops_builder/ref10/sc_muladd.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/sc_reduce.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/sign.c create mode 100644 monero_crypto/crypto_ops_builder/ref10/sqrtm1.h create mode 100644 monero_crypto/crypto_ops_builder/ref10/sqrtm1.py create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/MakeCryptoOps.py create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/api.h create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/base.h create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/base.py create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/base2.h create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/base2.py create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/crypto-ops.h create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/d.h create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/d.py create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/d2.h create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/d2.py create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/description create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/designers create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe.h create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_0.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_1.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_add.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_cmov.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_copy.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_frombytes.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_invert.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_isnegative.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_isnonzero.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_mul.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_neg.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_pow22523.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_sq.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_sq2.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_sub.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_tobytes.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge.h create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_add.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_add.h create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_add.q create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_double_scalarmult.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_frombytes.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_madd.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_madd.h create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_madd.q create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_msub.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_msub.h create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_msub.q create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p1p1_to_p2.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p1p1_to_p3.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p2_0.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p2_dbl.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p2_dbl.h create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p2_dbl.q create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p3_0.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p3_dbl.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p3_to_cached.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p3_to_p2.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p3_tobytes.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_precomp_0.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_scalarmult_base.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_sub.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_sub.h create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_sub.q create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_tobytes.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/keypair.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/open.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/pow22523.h create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/pow22523.q create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/pow225521.h create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/pow225521.q create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/q2h.sh create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/sc.h create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/sc_muladd.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/sc_reduce.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/sc_sub.xmr.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/scrap.txt create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/sign.c create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/sqrtm1.h create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/sqrtm1.py create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/test.py create mode 100644 monero_crypto/crypto_ops_builder/ref10CommentedCombined/xmrSpecificOld.c create mode 100755 monero_crypto/crypto_ops_builder/sha512-blocks.c create mode 100755 monero_crypto/crypto_ops_builder/sha512-hash.c create mode 100755 monero_crypto/crypto_ops_builder/sha512.h create mode 100755 monero_crypto/crypto_ops_builder/verify.c create mode 100644 monero_crypto/generic-ops.h create mode 100644 monero_crypto/groestl.c create mode 100644 monero_crypto/groestl.h create mode 100644 monero_crypto/groestl_tables.h create mode 100644 monero_crypto/hash-extra-blake.c create mode 100644 monero_crypto/hash-extra-groestl.c create mode 100644 monero_crypto/hash-extra-jh.c create mode 100644 monero_crypto/hash-extra-skein.c create mode 100644 monero_crypto/hash-ops.h create mode 100644 monero_crypto/hash.c create mode 100644 monero_crypto/hash.h create mode 100644 monero_crypto/initializer.h create mode 100644 monero_crypto/jh.c create mode 100644 monero_crypto/jh.h create mode 100644 monero_crypto/keccak.c create mode 100644 monero_crypto/keccak.h create mode 100644 monero_crypto/oaes_config.h create mode 100644 monero_crypto/oaes_lib.c create mode 100644 monero_crypto/oaes_lib.h create mode 100644 monero_crypto/random.c create mode 100644 monero_crypto/random.h create mode 100644 monero_crypto/skein.c create mode 100644 monero_crypto/skein.h create mode 100644 monero_crypto/skein_port.h create mode 100644 monero_crypto/slow-hash.c create mode 100644 monero_crypto/tree-hash.c create mode 100644 monero_crypto/warnings.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a5a03027f9..422a944ac8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,13 @@ set(DAP_CHAIN_SRCS dap_chain.c dap_chain_coin.c dap_chain_srv.c - dap_chain_tx.c) + dap_chain_tx.c + dap_hash.c + dap_hash_fusion.c + dap_hash_keccak.c + dap_hash_slow.c + + ) set(DAP_CHAIN_HEADERS dap_chain_block.h @@ -20,14 +26,24 @@ set(DAP_CHAIN_HEADERS dap_chain_coin.h dap_chain_srv.h dap_chain_tx.h + dap_hash.h + dap_hash_fusion.h + dap_hash_keccak.h + dap_hash_slow.h ) +add_subdirectory(monero_crypto) +include_directories("${monero_crypto_INCLUDE_DIRS}") +add_definitions ("${monero_crypto_DEFINITIONS}") + include_directories("${dap_core_INCLUDE_DIRS}") add_definitions ("${dap_core_DEFINITIONS}") include_directories("${dap_crypto_INCLUDE_DIRS}") add_definitions ("${dap_crypto_DEFINITIONS}") + + add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_SRCS} ${DAP_CHAIN_HEADERS}) set(${PROJECT_NAME}_DEFINITIONS CACHE INTERNAL "${PROJECT_NAME}: Definitions" FORCE) diff --git a/dap_chain.c b/dap_chain.c index 8a55788280..ba8ab0327a 100644 --- a/dap_chain.c +++ b/dap_chain.c @@ -19,4 +19,42 @@ */ -#include "dap_chain.h" \ No newline at end of file +#include "dap_chain.h" + +/** + * @brief dap_chain_open + * @param a_file_name + * @return + */ +dap_chain_t * dap_chain_open(const char * a_file_name) +{ + +} + +/** + * @brief dap_chain_remap + * @param a_chain + * @param a_offset + */ +void dap_chain_remap(dap_chain_t * a_chain, size_t a_offset) +{ + +} + +/** + * @brief dap_chain_save + * @param a_chain + */ +void dap_chain_save(dap_chain_t * a_chain) +{ + +} + +/** + * @brief dap_chain_close + * @param a_chain + */ +void dap_chain_close(dap_chain_t * a_chain) +{ + +} diff --git a/dap_chain.h b/dap_chain.h index 7907236d9e..f6f57f5d5c 100644 --- a/dap_chain.h +++ b/dap_chain.h @@ -18,13 +18,25 @@ along with any DAP based project. If not, see <http://www.gnu.org/licenses/>. */ - #ifndef _DAP_CHAIN_H_ #define _DAP_CHAIN_H_ +#include "dap_chain_block.h" + typedef struct dap_chain{ + dap_chain_block_t * mapped_block_first; // Mapped area start + dap_chain_block_t * mapped_block_last; // Last block in mapped area + uint64_t blocks_count; + void * _internal; void * _inhertor; } dap_chain_t; -#endif \ No newline at end of file +dap_chain_t * dap_chain_open(const char * a_file_name); + +void dap_chain_remap(dap_chain_t * a_chain, size_t a_offset); +void dap_chain_save(dap_chain_t * a_chain); + +void dap_chain_close(dap_chain_t * a_chain); + +#endif diff --git a/dap_chain_block.h b/dap_chain_block.h index f370e848af..25ab478c19 100644 --- a/dap_chain_block.h +++ b/dap_chain_block.h @@ -26,6 +26,7 @@ #include "dap_math_ops.h" #include "dap_chain_common.h" #include "dap_chain_block_section.h" +#include "dap_chain_block_roots.h" #define DAP_CHAIN_BLOCK_SIGNATURE 0xDA05BF8E @@ -35,16 +36,15 @@ */ typedef struct dap_chain_block{ struct { - uint32_t signature; /// Magic number, always equels to DAP_CHAIN_BLOCK_SIGNATURE - int32_t version; /// block version - dap_chain_hash_t prev_block_hash; - uint64_t timestamp; /// Timestamp - uint64_t bits; /// difficulty + uint32_t signature; /// @param signature @brief Magic number, always equels to DAP_CHAIN_BLOCK_SIGNATURE + int32_t version; /// @param version @brief block version (be carefull, signed value, as Bitcoin has) + dap_chain_hash_t prev_block; /// @param prev_block Hash of the previous block + dap_chain_hash_t root_main;/// @param root_main Main tree's root for all block's hashes + uint64_t timestamp; /// @param timestamp @brief Block create time timestamp + uint64_t difficulty; /// difficulty level uint64_t nonce; /// Nonce value to allow header variation for mining - dap_uint128_t id; /// @param id Block ID uniqie identificator of the block - size_t section_size; /// @param secion_size Size of section[] array + uint32_t section_size; /// @param secion_size Size of section[] array } header; - dap_chain_hash_t tree_root_; dap_chain_block_section_t section[]; } DAP_ALIGN_PACKED dap_chain_block_t; diff --git a/dap_chain_block_section.h b/dap_chain_block_section.h index df7fca5d11..a76e44090c 100644 --- a/dap_chain_block_section.h +++ b/dap_chain_block_section.h @@ -40,7 +40,7 @@ typedef struct dap_chain_block_section{ struct{ uint16_t type; // Section type - size_t size; // section size + uint32_t size; // section size } header; uint8_t data[]; // data } DAP_ALIGN_PACKED dap_chain_block_section_t; diff --git a/dap_chain_common.h b/dap_chain_common.h index 5fa776a25b..34a67094ba 100644 --- a/dap_chain_common.h +++ b/dap_chain_common.h @@ -2,6 +2,9 @@ #define _DAP_CHAIN_COMMON_H_ #include <stdint.h> +#include "dap_common.h" +#include "dap_math_ops.h" + #define DAP_CHAIN_HASH_SIZE 32 typedef union dap_chain_hash{ diff --git a/dap_chain_tx.c b/dap_chain_tx.c index e69de29bb2..a6c03c8818 100644 --- a/dap_chain_tx.c +++ b/dap_chain_tx.c @@ -0,0 +1,42 @@ +/* + Copyright (c) 2017-2018 (c) Project "DeM Labs Inc" https://github.com/demlabsinc + All rights reserved. + + This file is part of DAP (Deus Applications Prototypes) the open source project + + DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + DAP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with any DAP based project. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "dap_common.h" +#include "dap_chain_tx.h" + +#define LOG_TAG "dap_chain_tx" +/** + * @brief dap_chain_tx_init + * @return + */ +int dap_chain_tx_init() +{ + log_it(L_INFO,"DapChain Transactions module init"); + return 0; +} + +/** + * @brief dap_chain_tx_deinit + */ +void dap_chain_tx_deinit() +{ + log_it(L_INFO,"DapChain Transactions module deinit"); +} + diff --git a/dap_chain_tx.h b/dap_chain_tx.h index e69de29bb2..74bd78ed3f 100644 --- a/dap_chain_tx.h +++ b/dap_chain_tx.h @@ -0,0 +1,29 @@ +/* + Copyright (c) 2017-2018 (c) Project "DeM Labs Inc" https://github.com/demlabsinc + All rights reserved. + + This file is part of DAP (Deus Applications Prototypes) the open source project + + DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + DAP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with any DAP based project. If not, see <http://www.gnu.org/licenses/>. +*/ +#ifndef _DAP_CHAIN_TX_H_ +#define _DAP_CHAIN_TX_H_ + +#include "dap_chain_common.h" + +int dap_chain_tx_init(); +void dap_chain_tx_deinit(); + +#endif + diff --git a/dap_hash.c b/dap_hash.c new file mode 100644 index 0000000000..c8d3a7fe20 --- /dev/null +++ b/dap_hash.c @@ -0,0 +1,4 @@ +#include "dap_common.h" +#include "dap_hash.h" + +#define LOG_TAG "dap_hash" diff --git a/dap_hash.h b/dap_hash.h new file mode 100644 index 0000000000..a3b57560b9 --- /dev/null +++ b/dap_hash.h @@ -0,0 +1,30 @@ +#ifndef _DAP_HASH_H_ +#define _DAP_HASH_H_ +#include <stddef.h> + +#include "dap_hash_slow.h" +#include "dap_hash_keccak.h" + + + +typedef enum dap_hash_type { + DAP_HASH_TYPE_KECCAK = 0, + DAP_HASH_TYPE_SLOW_0 = 1, +} dap_hash_type_t; + +inline void dap_hash(void * a_data_in, size_t a_data_in_size, + void * a_data_out, size_t a_data_out_size, + dap_hash_type_t a_type ){ + switch (a_type){ + case DAP_HASH_TYPE_KECCAK: + dap_hash_keccak(a_data_in,a_data_in_size, a_data_out,a_data_out_size); + break; + case DAP_HASH_TYPE_SLOW_0: + if( a_data_out_size>= dap_hash_slow_size() ){ + dap_hash_slow(a_data_in,a_data_in_size,(char*) a_data_out); + } + break; + } + +} +#endif diff --git a/dap_hash_fusion.c b/dap_hash_fusion.c new file mode 100644 index 0000000000..e1a46eeb2b --- /dev/null +++ b/dap_hash_fusion.c @@ -0,0 +1,4 @@ +#include "dap_common.h" +#include "dap_hash_fusion.h" + +#define LOG_TAG "dap_hash_fusion" diff --git a/dap_hash_fusion.h b/dap_hash_fusion.h new file mode 100644 index 0000000000..12346aaae7 --- /dev/null +++ b/dap_hash_fusion.h @@ -0,0 +1,5 @@ +#ifndef _DAP_HASH_FUSION_H_ +#define _DAP_HASH_FUSION_H_ + + +#endif diff --git a/dap_hash_keccak.c b/dap_hash_keccak.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/dap_hash_keccak.h b/dap_hash_keccak.h new file mode 100644 index 0000000000..6381fe4923 --- /dev/null +++ b/dap_hash_keccak.h @@ -0,0 +1,10 @@ +#pragma once +#include "keccak.h" + + +inline void dap_hash_keccak(const void * a_in, size_t a_in_size, void * a_out, size_t a_out_size) +{ + keccak((const uint8_t*) a_in,a_in_size, (uint8_t *) a_out, a_out_size ); +} + + diff --git a/dap_hash_slow.c b/dap_hash_slow.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/dap_hash_slow.h b/dap_hash_slow.h new file mode 100644 index 0000000000..61a90525ed --- /dev/null +++ b/dap_hash_slow.h @@ -0,0 +1,21 @@ +#ifndef _DAP_HASH_SLOW_H_ +#define _DAP_HASH_SLOW_H_ + +#include "hash-ops.h" + +#define DAP_HASH_SLOW_SIZE HASH_SIZE + +/** + * @brief dap_hash_slow + * @param a_in + * @param a_in_length + * @param a_out Must be allocated with enought space + */ +inline void dap_hash_slow(const void *a_in, size_t a_in_length, char * a_out) +{ + cn_slow_hash(a_in,a_in_length,a_out); +} + +inline size_t dap_hash_slow_size() { return DAP_HASH_SLOW_SIZE; } +//cn_slow_hash(data, length, reinterpret_cast<char *>(&hash)); +#endif diff --git a/hash_fusion/Makefile.old b/hash_fusion/Makefile.old new file mode 100644 index 0000000000..5c6482dad5 --- /dev/null +++ b/hash_fusion/Makefile.old @@ -0,0 +1,105 @@ +# HashFusion Makefile +# April 2017 +# +# Author: brian.monahan@hpe.com +# +# (c) Copyright 2017 Hewlett Packard Enterprise Development LP +# +# 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. +# +# 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. + +SHELL = /bin/sh + +PWD = $(shell pwd) +CC ?= gcc # gcc clang + +# Variables +PROG := hmt + +# Source Directories +LIBDIR := $(PWD)/lib +APPDIR := $(PWD)/app + +# Set source directory paths +VPATH = $(LIBDIR) $(APPDIR) + +# Binary/Object Directories +BINDIR := $(PWD)/bin +OBJDIR := $(PWD)/obj + +# Library paths and compiler options +CRYPTO := -L/usr/local/lib -L/usr/local/ssl/lib -lcrypto +LDOPTS := -ldl -lm $(CRYPTO) # -lm -lssl + +INCLUDES := -iquote$(LIBDIR) -I/usr/local/ssl/include +CODEOPTS := -D SUPPRESS_REQUIRES_CHECKING -D SUPPRESS_NEEDS_CHECKING -D USE_MALLOC_AND_FREE # +COPTS := -O3 -finline-functions $(CODEOPTS) # -finline-functions -O2 -O3 + +CFLAGS := -std=c99 $(COPTS) -Werror -Winline $(INCLUDES) # -Wall -g + +APPS := $(wildcard $(APPDIR)/*.c) +LIBS := $(wildcard $(LIBDIR)/*.c) + +ALL_APPS := $(PROG) + +OBJS := $(LIBS:$(LIBDIR)/%.c=$(OBJDIR)/%.o) # standard lib objects + +# Empty .SUFFIXES rule to defeat built-in rules +.SUFFIXES: ; + +# PHONY targets (i.e. commands) +.PHONY: help build rebuild clean + +help : + @echo + @echo " clean : Cleans directory" + @echo " build : Build $(PROG)" + @echo " rebuild : First clean directory then build" + +build : + @make clean + @make hmt + +clean : + @echo "Cleaning ..." + @rm -rf $(BINDIR) + @rm -rf $(OBJDIR) + @mkdir -p $(BINDIR) + @mkdir -p $(OBJDIR) + @rm -f *.exe *.plist *.o *.s *.bc *.stackdump a.out + +hmt :: $(OBJDIR)/hmt.o $(OBJS) + @echo + @echo Linking objects for: $@ + @$(CC) -o $@ $^ $(LDOPTS) + @mkdir -p $(BINDIR) + @mv $@ $(BINDIR) + @echo Contents of: $(BINDIR) + @ls -l $(BINDIR) + @echo + +$(OBJDIR)/%.o :: %.c utils.h + @echo Compiling lib object $@ + @mkdir -p $(OBJDIR) + @$(CC) -o $@ $(CFLAGS) -c $< + diff --git a/hash_fusion/example/hmt.c b/hash_fusion/example/hmt.c new file mode 100644 index 0000000000..34e33fe3fd --- /dev/null +++ b/hash_fusion/example/hmt.c @@ -0,0 +1,973 @@ +/* hmt.c + + Hash Fusion/Merkle Tree testing application + + Application for examining/comparing the effect of different configurations and settings. + + The basic experiment consists of: + 1) Generating a sequence of data blocks + 2) Calculating a hash of the given blocks (computed in sequence). + (a) This could use accumulation structure to build hash (albeit trivial). + (b) No accumulation - simply directly add to end. + 3) Randomising the blocks. + 4) Rehashing the sequence of blocks, using a given accumulation structure + to build the hash. + 5) Compare blocks ... (should be identical) + + The properties that can be varied include + - The kind of accumulation structure used. + - The first hash could be accumulated sequentially without using accumulation sequence. + - Number of repetitions to obtain an time average (+ indication of variance.) + - blocksize used + - Number of blocks + range of number of blocks + - Output format: console output/CSV output /JSON output + + Author: brian.monahan@hpe.com + + (c) Copyright 2017 Hewlett Packard Enterprise Development LP + + 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. + + 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. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "utils.h" +#include "alloc.h" +#include "random.h" +#include "testLib.h" +#include "stringbuffer.h" + +//////////////////////////////////////////////////////////////////////////////// +// Types and Structs +//////////////////////////////////////////////////////////////////////////////// + +typedef enum { + HASHFUSION_ONLY_TESTMODE = 2000, // HashFusion only + MERKLETREE_ONLY_TESTMODE, // Merkle Tree only + DEFAULT_TESTMODE // Default only + } TestMode_t; + +typedef enum { + CONSOLE_OUTPUT_MODE = 2010, // Console putput mode + CSV_OUTPUT_MODE, // CSV output mode + JSON_OUTPUT_MODE // JSON output mode + } OutputMode_t; + +typedef enum { + HASHFUSION_METHOD, // HashFusion method + MERKLETREE_METHOD, // Merkle Tree method + } MethodType_t; + +typedef struct reportObj Report_t; + +struct reportObj { + MethodType_t method; + int seed; + int blocksize; + int numBlocks; + int dataSize; + int runs; + HFuseAccum_t accumType; + double initialTime; + double initialDataRate; + double destTime; + double destDataRate; +}; + +//////////////////////////////////////////////////////////////////////////////// +// Control Properties +//////////////////////////////////////////////////////////////////////////////// +static unsigned int argSeed = 27652761; +static int argTotalBlocks = 50; +static int argBlockSize = 1024; +static int argRuns = 1; + +static TestMode_t argTestMode = DEFAULT_TESTMODE; // Test mode +static Boolean_t argSendOnly = FALSE; // Send only? Otherwise do both send/receive + +static HFuseAccum_t argAccumKind = TREE_SET_ACCUM_HF; // LINEAR_LIST_ACCUM_HF; DIRECT_ACCUM_HF; + +static OutputMode_t argOutputMode = CONSOLE_OUTPUT_MODE; + +// Total data (in bytes) +static long totalData = 0; + +// Digests (hash fusion) +static Digest_t *resultDigest_src_hf = NULL; +static Digest_t *resultDigest_dest_hf = NULL; + +static double srcTimeInSecs_hf = 0.0; +static double destTimeInSecs_hf = 0.0; + +// Merkle Tree info +static Digest_t *resultDigest_src_mt = NULL; +static Digest_t *resultDigest_dest_mt = NULL; + +static double srcTimeInSecs_mt = 0.0; +static double destTimeInSecs_mt = 0.0; + +// Report objects +#define UPDATE_REPORT(rep, fld, val) { if ((rep) != NULL) {rep->fld = (val); }} + +static Report_t *report_hf = NULL; +static Report_t *report_mt = NULL; + +//////////////////////////////////////////////////////////////////////////////// +// Display Enum types +//////////////////////////////////////////////////////////////////////////////// +static char *show_TestMode(TestMode_t val) { + switch (val) { + case HASHFUSION_ONLY_TESTMODE: return "HASHFUSION_ONLY_TESTMODE"; + case MERKLETREE_ONLY_TESTMODE: return "MERKLETREE_ONLY_TESTMODE"; + case DEFAULT_TESTMODE: return "DEFAULT_TESTMODE"; + + default: + diagnostic("show_TestMode: Expected a TestMode_t value - got instead: %i", val); + error_exit(); + } +} + + +static char *show_OutputMode(OutputMode_t val) { + switch (val) { + case CONSOLE_OUTPUT_MODE: return "CONSOLE_OUTPUT_MODE"; + case CSV_OUTPUT_MODE: return "CSV_OUTPUT_MODE"; + case JSON_OUTPUT_MODE: return "JSON_OUTPUT_MODE"; + + default: + diagnostic("show_OutputMode: Expected a OutputMode_t value - got instead: %i", val); + error_exit(); + } +} + + +static char *show_MethodType(MethodType_t val) { + switch (val) { + case HASHFUSION_METHOD: return "HASHFUSION_METHOD"; + case MERKLETREE_METHOD: return "MERKLETREE_METHOD"; + + default: + diagnostic("show_MethodType: Expected a MethodType_t value - got instead: %i", val); + error_exit(); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// Usage +//////////////////////////////////////////////////////////////////////////////// +#undef NL +#undef SP + +#define NL "\n" +#define SP " " + +static void usage() { + char *usageString = + "Usage: hmt <options>" NL + NL + " This app provides command-line performance tests of hash-fusion code" NL + " compared with using Merkle Trees." NL + NL + " The basic experiment consists of:" NL + " 1) Generating a sequence of randomised data blocks" NL + " 2) Calculating hash of the given block (computed in sequence)." NL + " 3) Randomise the order of the blocks so that they are presented in randomised sequence." NL + " 4) Rehash the out-of-order sequence of blocks by using a specified accumulation structure." NL + " to build the required in-order hash." NL + " 5) Compare the two hashes ... (hashes should be identical)" NL + " 6) Report statistics (e.g. timing averages)" NL + NL + " The following options are supported:" NL + NL + " -a <accum-type> : Accumulation structure (either d: direct, l: linear, t: tree)" NL + " (default: t)." NL + NL + " -s <seed-value> : Seed value for generating random data. Setting this to" NL + " zero provides a seed determined by date/time" NL + " (default: 27652761)." NL + NL + " -h : HashFusion only." NL + NL + " -m : Merkle Tree only." NL + NL + " -r <runs> : Number of runs (default: 1)." NL + NL + " -n <blocks> : Number of blocks. (default: 50)" NL + NL + " -b <block-size> : Size of each data block (default: 1024 bytes)." NL + NL + " -csv : CSV format report output -- reports stats using csv output format." NL + " This format will output the column header line once." NL + NL + " -json : JSON format report output." NL + NL + " The block-size and number of blocks options can use a multiplier code (k = 1024)." NL + NL + " When using the 'direct' accumulation structure, it doesn't make sense to deal with out-of-order" NL + " data. In this case, only the first two (and final) steps are performed." NL + NL + " Examples:" NL + " hmt -s 236483624 -b 8k -n 22k -r 20" NL + " -- Use seed 236483624, blocksize = 8192, number of blocks = 22528, runs = 20" NL + " and default binary tree accumulation structure" NL + NL + " hmt -s 4526263 -b 4k -n 2k -r 30 -a l" NL + " -- Use seed 4526263, blocksize = 4096, number of blocks = 2048, runs = 30" NL + " and use the linear list accumulation structure" NL + NL + " hmt -b 6035 -h -n 16k -r 25" NL + " -- Use default seed, blocksize = 6035, perform HashFusion only, number " NL + " of blocks = 16384, and runs = 25" NL + ; + + printf("%s", usageString); + exit(0); +} + + +//////////////////////////////////////////////////////////////////////////////// +// Process arguments +//////////////////////////////////////////////////////////////////////////////// + +// Argument codes +#define ARG_SEED 's' +#define ARG_BLOCK_SIZE 'b' +#define ARG_NUM_BLOCKS '#' +#define ARG_RUNS 'r' +#define ARG_ACCUM_TYPE 'a' + +static void processArgs(int argc, char *argv[]) { + char *argStr = NULL; + + char code; + + char str[STD_BUFSIZE]; + int intVal; + + // This encodes if the current arg is expected to encode data ... + Boolean_t isDataArg = FALSE; + Byte_t dataArgCode = 0; + + if (argc == 1) { + usage(); + } + + for (int i=1; i < argc; i++) { + argStr = argv[i]; + toLowerCase(argStr); // lower case the argument string ... + + //printf("%i. %s\n", i, argStr); + + if (dataArgCode != 0) { + switch (dataArgCode) { + case ARG_SEED: + if (sscanf(argStr, "%i", &argSeed) == 1) { + if (argSeed < 0) argSeed = -argSeed; + } + else { + diagnostic("Expected an integer ... got instead: %s", argStr); + error_exit(); + } + break; + + case ARG_BLOCK_SIZE: + if (sscanf(argStr, "%i%c", &argBlockSize, &code) == 2) { + switch (code) { + case 'k': argBlockSize *= 1024; break; + default: + diagnostic("Expected an integer followed by multiplier (k) ... got instead: %s", argStr); + error_exit(); + } + } + else if (sscanf(argStr, "%i", &argBlockSize) > 0) { + // SKIP - NO CODE + } + else { + diagnostic("Expected an integer ... got instead: %s", argStr); + error_exit(); + } + + // Limit value of argBlockSize + argBlockSize = minmax(1, argBlockSize, 128 * 1024); + break; + + case ARG_NUM_BLOCKS: + if (sscanf(argStr, "%i%c", &argTotalBlocks, &code) == 2) { + switch (code) { + case 'k': argTotalBlocks *= 1024; break; + default: + diagnostic("Expected an integer followed by multiplier (k) ... got instead: %s", argStr); + error_exit(); + } + } + else if (sscanf(argStr, "%i", &argTotalBlocks) > 0) { + // SKIP - NO CODE + } + else { + diagnostic("Expected an integer ... got instead: %s", argStr); + error_exit(); + } + + // Limit value of argTotalBlocks + argTotalBlocks = minmax(1, argTotalBlocks, 32 * 1024); + break; + + case ARG_RUNS: + if (sscanf(argStr, "%i", &argRuns) == 1) { + argRuns = min(argRuns, 100); + + if (argRuns < 1) { + diagnostic("Number of runs should be positive: %s", argStr); + error_exit(); + } + } + else { + diagnostic("Expected an integer ... got instead: %s", argStr); + error_exit(); + } + + // Limit value of argRuns + argRuns = minmax(1, argRuns, 256); + break; + + case ARG_ACCUM_TYPE: + if (sscanf(argStr, "%c", &code) == 1) { + argSendOnly = FALSE; + switch (code) { + case 'd': argAccumKind = DIRECT_ACCUM_HF; argSendOnly = TRUE; break; + case 'l': argAccumKind = LINEAR_LIST_ACCUM_HF; break; + case 't': argAccumKind = TREE_SET_ACCUM_HF; break; + default: + diagnostic("Expected a code specifying accumulation structure (e.g. d, l or t) ... got instead: %s", argStr); + error_exit(); + } + } + else { + diagnostic("Expected a character specifying accumulation structure (e.g. d, l or t) ... got instead: %s", argStr); + error_exit(); + } + break; + + default: + diagnostic("Unexpected data element: %s", argStr); + error_exit(); + } + + dataArgCode = 0; + continue; + } + + dataArgCode = 0; + + // seed option + if (strncmp("-s", argStr, 2) == 0) { + dataArgCode = ARG_SEED; + continue; + } + + // block-size option + if (strncmp("-b", argStr, 2) == 0) { + dataArgCode = ARG_BLOCK_SIZE; + continue; + } + + // hash-fusion only option + if (strncmp("-h", argStr, 2) == 0) { + argTestMode = HASHFUSION_ONLY_TESTMODE; + report_hf = ALLOC_OBJ(Report_t); + + continue; + } + + // merkle tree only option + if (strncmp("-m", argStr, 2) == 0) { + argTestMode = MERKLETREE_ONLY_TESTMODE; + report_mt = ALLOC_OBJ(Report_t); + + continue; + } + + // number of blocks option + if (strncmp("-n", argStr, 2) == 0 || strncmp("-#", argStr, 2) == 0) { + dataArgCode = ARG_NUM_BLOCKS; + continue; + } + + if (strncmp("-r", argStr, 2) == 0) { + dataArgCode = ARG_RUNS; + continue; + } + + // accumulation type option + if (strncmp("-a", argStr, 2) == 0) { + dataArgCode = ARG_ACCUM_TYPE; + continue; + } + + // csv format option + if (strncmp("-c", argStr, 2) == 0) { + argOutputMode = CSV_OUTPUT_MODE; + continue; + } + + // json format option + if (strncmp("-j", argStr, 2) == 0) { + argOutputMode = JSON_OUTPUT_MODE; + continue; + } + + // unrecognised option & help option + if (strncmp("-", argStr, 1) == 0) { + usage(); + } + + // Error - unexpected argument + diagnostic("Unexpected argument: %s", argStr); + error_exit(); + } + + // Ensure definition of reports in default testmode ... + if (argTestMode == DEFAULT_TESTMODE) { + report_hf = ALLOC_OBJ(Report_t); + report_mt = ALLOC_OBJ(Report_t); + } + + /* + if (DONT) { + printf("\nApplication state set to:\n"); + printf(" argSeed = %i\n", argSeed); + printf(" argTotalBlocks = %i\n", argTotalBlocks); + printf(" argBlockSize = %i\n", argBlockSize); + printf(" argRuns = %i\n", argRuns); + printf(" argAccumKind = %s\n", show_HFuseAccum(argAccumKind)); + printf(" argTestMode = %s\n", show_TestMode(argTestMode)); + printf(" argOutputMode = %s\n", show_OutputMode(argOutputMode)); + printf(" argSendOnly = %s\n", showBoolean(argSendOnly)); + printf("\n"); + + //exit(0); + } + */ + + //exit(0); +} + +//////////////////////////////////////////////////////////////////////////////// +// Output reporting +//////////////////////////////////////////////////////////////////////////////// +static void consoleOut(const char *fmt, ...) { + if (argOutputMode != CONSOLE_OUTPUT_MODE) return; + va_list args; + + va_start(args, fmt); + vfprintf(stdout, fmt, args); + va_end(args); +} + +static char statsReportBuf[MSG_BUFSIZE+1]; + +static Report_t *new_Report() { + return ALLOC_OBJ(Report_t); +} + +static char csvHeader[] = "Method, Seed, Blocksize, NumBlocks, Datasize, Runs, AccumType, " + "Initial Time, Initial Data Rate, Destination Time, Destination Data Rate\n"; + +static Boolean_t csvHeaderShown = FALSE; + +static void csvOut(Report_t *rep) { + if (rep == NULL) return; + if (argOutputMode != CSV_OUTPUT_MODE) return; + + if (!csvHeaderShown) { + printf("%s", csvHeader); + csvHeaderShown = TRUE; + } + + printf("\"%s\", ", show_MethodType(rep->method)); + printf("%i, ", rep->seed); + printf("%i, ", rep->blocksize); + printf("%i, ", rep->numBlocks); + printf("%i, ", rep->dataSize); + printf("%i, ", rep->runs); + printf("\"%s\", ", (rep->accumType == 0 ? "" : show_HFuseAccum(rep->accumType))); + printf("%5f, ", rep->initialTime); + printf("%5f, ", rep->initialDataRate); + printf("%5f, ", rep->destTime); + printf("%5f\n", rep->destDataRate); +} + +static void jsonOut(Report_t *rep) { + if (rep == NULL) return; + if (argOutputMode != JSON_OUTPUT_MODE) return; + + printf("{method:\"%s\", ", show_MethodType(rep->method)); + printf("seed:%i, ", rep->seed); + printf("blocksize:%i, ", rep->blocksize); + printf("numblocks:%i, ", rep->numBlocks); + printf("datasize:%i, ", rep->dataSize); + printf("runs:%i, ", rep->runs); + printf("accum-type:\"%s\", ", (rep->accumType == 0 ? "" : show_HFuseAccum(rep->accumType))); + printf("initial-time:%5f, ", rep->initialTime); + printf("initial-data-rate:%5f, ", rep->initialDataRate); + printf("dest-time:%5f, ", rep->destTime); + printf("dest-data-rate:%5f}", rep->destDataRate); +} + + +//////////////////////////////////////////////////////////////////////////////// +// Methods +//////////////////////////////////////////////////////////////////////////////// +void runSrc_FusionStruct() { + + // Compute digest value + Digest_t *curDigest = calcDigest_FusionStruct(NULL); + + if (getHashState_DG(curDigest) != HST_FINAL) { + diagnostic("runSrc_FusionStruct: digest was not finalised: digest state = %s", showHashState_DG(curDigest)); + error_exit(); + } + + if (resultDigest_src_hf == NULL) { + // Transfer curDigest to resultDigest_src_hf + resultDigest_src_hf = curDigest; + curDigest = NULL; + } + else if (!isEqual_DG(resultDigest_src_hf, curDigest)) { + StringBuf_t *sBuf = new_SB(); + + addItems_SB(sBuf, "runSrc_FusionStruct: digests not equal:\n"); + addItems_SB(sBuf, " resultDigest_src_hf digest = 0x%s\n", showHexHashValue_DG(resultDigest_src_hf)); + addItems_SB(sBuf, " current digest = 0x%s", showHexHashValue_DG(curDigest)); + + error_exit_SB(sBuf); + } + + // Deallocate the current digest ... + deallocate_DG(curDigest); +} + +void runDest_FusionStruct() { + + // Compute digest value + Digest_t *curDigest = calcDigest_FusionStruct(destBlocksPerm); + + if (getHashState_DG(curDigest) != HST_FINAL) { + diagnostic("runDest_FusionStruct: digest was not finalised: digest state = %s", showHashState_DG(curDigest)); + error_exit(); + } + + if (resultDigest_dest_hf == NULL) { + // Transfer curDigest to resultDigest_dest_hf + resultDigest_dest_hf = curDigest; + curDigest = NULL; + } + else if (!isEqual_DG(resultDigest_dest_hf, curDigest)) { + StringBuf_t *sBuf = new_SB(); + + addItems_SB(sBuf, "runDest_FusionStruct: digests not equal:\n"); + addItems_SB(sBuf, " resultDigest_dest_hf digest = 0x%s\n", showHexHashValue_DG(resultDigest_dest_hf)); + addItems_SB(sBuf, " current digest = 0x%s", showHexHashValue_DG(curDigest)); + + error_exit_SB(sBuf); + } + + // Deallocate the current digest ... + deallocate_DG(curDigest); +} + + +static void runSrc_MerkleTree() { + + // Compute digest value + Digest_t *curDigest = calcDigest_MerkleTree(NULL); + + if (getHashState_DG(curDigest) != HST_FINAL) { + diagnostic("runSrc_MerkleTree: digest was not finalised: digest state = %s", showHashState_DG(curDigest)); + error_exit(); + } + + if (resultDigest_src_mt == NULL) { + // Transfer curDigest to resultDigest_src_mt + resultDigest_src_mt = curDigest; + curDigest = NULL; + } + else if (!isEqual_DG(resultDigest_src_mt, curDigest)) { + StringBuf_t *sBuf = new_SB(); + + addItems_SB(sBuf, "runSrc_MerkleTree: digests not equal:\n"); + addItems_SB(sBuf, " resultDigest_src_mt digest = 0x%s\n", showHexHashValue_DG(resultDigest_src_mt)); + addItems_SB(sBuf, " current digest = 0x%s", showHexHashValue_DG(curDigest)); + + error_exit_SB(sBuf); + } + + // Deallocate the current digest ... + deallocate_DG(curDigest); +} + +void runDest_MerkleTree() { + + // Compute digest value + Digest_t *curDigest = calcDigest_MerkleTree(destBlocksPerm); + + if (getHashState_DG(curDigest) != HST_FINAL) { + diagnostic("runDest_FusionStruct: digest was not finalised: digest state = %s", showHashState_DG(curDigest)); + error_exit(); + } + + if (resultDigest_dest_mt == NULL) { + // Transfer curDigest to resultDigest_dest_mt + resultDigest_dest_mt = curDigest; + curDigest = NULL; + } + else if (!isEqual_DG(resultDigest_dest_mt, curDigest)) { + StringBuf_t *sBuf = new_SB(); + + addItems_SB(sBuf, "runDest_MerkleTree: digests not equal:\n"); + addItems_SB(sBuf, " resultDigest_dest_mt digest = 0x%s\n", showHexHashValue_DG(resultDigest_dest_mt)); + addItems_SB(sBuf, " current digest = 0x%s", showHexHashValue_DG(curDigest)); + + error_exit_SB(sBuf); + } + + // Deallocate the current digest ... + deallocate_DG(curDigest); +} + +// This code ensures that various memory caches have been flushed/overwritten. +static unsigned int *memFlushBuf = NULL; +static void flushMemoryCaches() { + int memSize = 5 * 1024 * 1024; + + memFlushBuf = ALLOC_ARR(memSize, unsigned int); + + // load the memory with random data + for (int i = 0; i < memSize; i++) { + memFlushBuf[i] = nextRandom(); + } + + // Do some meaningless computation that uses the memory ... + unsigned int limit = pow2(17) + 5; + unsigned int sum = 0; + for (int i = memSize-1; 0 <= i; i--) { + sum += memFlushBuf[i]; + if (sum >= limit) { + sum = 0; + } + } + + free(memFlushBuf); + + memFlushBuf = NULL; +} + +//////////////////////////////////////////////////////////////////////////////// +// Run tests +//////////////////////////////////////////////////////////////////////////////// + +static void produceResults() { + // Produce results ... + if (argTestMode != MERKLETREE_ONLY_TESTMODE) { + double srcDataRate_hf = totalData/(1024 * 1024 * srcTimeInSecs_hf); + + consoleOut("\n\nHashFusion:\n"); + consoleOut(" Source build-time: %.5f secs (data rate: %.5f MB/sec)\n", srcTimeInSecs_hf, srcDataRate_hf); + + // update report + UPDATE_REPORT(report_hf, initialDataRate, srcDataRate_hf); + + if (!argSendOnly) { + double destDataRate_hf = totalData/(1024 * 1024 * destTimeInSecs_hf); + + consoleOut(" Dest. build-time: %.5f secs (data rate: %.5f MB/sec)\n", destTimeInSecs_hf, destDataRate_hf); + + // update report + UPDATE_REPORT(report_hf, destDataRate, destDataRate_hf); + } + } + + if (argTestMode != HASHFUSION_ONLY_TESTMODE) { + double srcDataRate_mt = totalData/(1024 * 1024 * srcTimeInSecs_mt); + + consoleOut("\n\nMerkle hash tree:\n"); + consoleOut(" Source build-time: %.5f secs (data rate: %.5f MB/sec)\n", srcTimeInSecs_mt, srcDataRate_mt); + + // update report + UPDATE_REPORT(report_mt, initialDataRate, srcDataRate_mt); + + if (!argSendOnly) { + double destDataRate_mt = totalData/(1024 * 1024 * destTimeInSecs_mt); + + consoleOut(" Dest. build-time: %.5f secs (data rate: %.5f MB/sec)\n", destTimeInSecs_mt, destDataRate_mt); + + // update report + UPDATE_REPORT(report_mt, destDataRate, destDataRate_mt); + + } + } + + // stats output + csvOut(report_hf); + csvOut(report_mt); + + jsonOut(report_hf); + jsonOut(report_mt); +} + +void runTest () { + consoleOut("Hashfusion-Merkle tree Testing tool (HMT)\n"); + consoleOut("-- Testing pure data transfer with randomisation\n"); + + //debugOn = FALSE; + //checkAllocation_MM = FALSE; + //checkDeallocation_MM = FALSE; + + setSeed(argSeed); + consoleOut("-- Current seed value: %i\n", getSeed() ); + + blockSize = argBlockSize; + totalBlocks = argTotalBlocks; + argRuns = max(1, argRuns); + accumKind = argAccumKind; + + totalData = (long)(blockSize * totalBlocks); + + + // Update report values + // + // MethodType_t method; + // int seed; + // int blocksize; + // int numBlocks; + // int dataSize; + // int runs; + // HFuseAccum_t accumType; + // double initialTime; + // double initialDataRate; + // double destTime; + // double destDataRate; + // + UPDATE_REPORT(report_hf, method, HASHFUSION_METHOD); + UPDATE_REPORT(report_mt, method, MERKLETREE_METHOD); + + UPDATE_REPORT(report_hf, seed, argSeed); + UPDATE_REPORT(report_mt, seed, argSeed); + + UPDATE_REPORT(report_hf, blocksize, blockSize); + UPDATE_REPORT(report_mt, blocksize, blockSize); + + UPDATE_REPORT(report_hf, numBlocks, totalBlocks); + UPDATE_REPORT(report_mt, numBlocks, totalBlocks); + + UPDATE_REPORT(report_hf, dataSize, totalData); + UPDATE_REPORT(report_mt, dataSize, totalData); + + UPDATE_REPORT(report_hf, runs, argRuns); + UPDATE_REPORT(report_mt, runs, argRuns); + + UPDATE_REPORT(report_hf, accumType, accumKind); + UPDATE_REPORT(report_mt, accumType, NULL_VAL); // accumType not relevant to Merkle Tree + + // Output accumulation info + switch (accumKind) { + case DIRECT_ACCUM_HF: consoleOut("-- Using Direct accumulation (%i).\n", accumKind); break; + case LINEAR_LIST_ACCUM_HF: consoleOut("-- Using Linear list accumulation structure (%i).\n", accumKind); break; + case TREE_SET_ACCUM_HF: consoleOut("-- Using Red-Black tree set accumulation structure (%i).\n", accumKind); break; + default: + diagnostic("runTest: accumKind not set to good value: %i", accumKind); + error_exit(); + } + + consoleOut("\nInitialising data blocks ...\n"); + consoleOut(" -- Block size: %i\n", blockSize); + consoleOut(" -- Number of (randomised) data blocks: %i\n", totalBlocks); + consoleOut(" -- Amount of data: %li bytes\n", totalData); + + initialiseTestData(); + populateBlocks(); + + // Build the source hash structure + consoleOut("\nBuilding source hash structures ... (Runs: %i)\n", argRuns); + double totalSrcTimeInSecs_hf = 0; + double totalSrcTimeInSecs_mt = 0; + + if (argTestMode != MERKLETREE_ONLY_TESTMODE) { + consoleOut(" -- Using HashFusion ...\n"); + totalSrcTimeInSecs_hf = timeFunction2( argRuns, flushMemoryCaches, runSrc_FusionStruct ); + } + + if (argTestMode != HASHFUSION_ONLY_TESTMODE) { + consoleOut(" -- Using MerkelTree ...\n"); + totalSrcTimeInSecs_mt = timeFunction2( argRuns, flushMemoryCaches, runSrc_MerkleTree ); + } + + // calc average + srcTimeInSecs_hf = totalSrcTimeInSecs_hf/argRuns; + srcTimeInSecs_mt = totalSrcTimeInSecs_mt/argRuns; + + // update reports for initialTime + UPDATE_REPORT(report_hf, initialTime, srcTimeInSecs_hf); + UPDATE_REPORT(report_mt, initialTime, srcTimeInSecs_mt); + + if (argSendOnly) { + produceResults(); + return; + } + + // Simulates the act of receiving the data in some order at the destination + consoleOut("\nRandomise destination order ...\n"); + randomiseDestOrder(); + + consoleOut("\nDestination Order of Data Blocks\n"); + int showBlocks = min(5, totalBlocks); + + for (int i = 0; i < showBlocks; i++) { + consoleOut(" destBlocksPerm[%i] = %i\n", i, destBlocksPerm[i]); + } + + if (showBlocks != totalBlocks) { + int i = totalBlocks-1; + consoleOut(" ...\n"); + consoleOut(" destBlocksPerm[%i] = %i\n", i, destBlocksPerm[i]); + } + + // Run the destination Hash Fusion structure + consoleOut("\nBuilding the destination hash structure ... (Runs: %i)\n", argRuns); + double totalDestTimeInSecs_hf = 0; + double totalDestTimeInSecs_mt = 0; + + if (argTestMode != MERKLETREE_ONLY_TESTMODE) { + consoleOut(" -- Using HashFusion ...\n"); + totalDestTimeInSecs_hf = timeFunction2( argRuns, flushMemoryCaches, runDest_FusionStruct ); + } + + if (argTestMode != HASHFUSION_ONLY_TESTMODE) { + consoleOut(" -- Using MerkelTree ...\n"); + totalDestTimeInSecs_mt = timeFunction2( argRuns, flushMemoryCaches, runDest_MerkleTree ); + } + + // calc average + destTimeInSecs_hf = totalDestTimeInSecs_hf/argRuns; + destTimeInSecs_mt = totalDestTimeInSecs_mt/argRuns; + + // Update reports for destTime + UPDATE_REPORT(report_hf, destTime, destTimeInSecs_hf); + UPDATE_REPORT(report_mt, destTime, destTimeInSecs_mt); + + // Console Results + if (argTestMode == DEFAULT_TESTMODE) { + // Compare results + consoleOut("\nComparing results ...\n"); + + if (resultDigest_src_hf != NULL && resultDigest_dest_hf != NULL && isEqual_DG(resultDigest_src_hf, resultDigest_dest_hf)) { + consoleOut("\nSUCCESS! same hashes - using HashFusion:\n 0x%s\n", showHexHashValue_DG(resultDigest_src_hf)); + } + else { + consoleOut("\nFAILED! Different HashFusion hashes:\n"); + consoleOut(" Source hash value = 0x%s\n", showHexHashValue_DG(resultDigest_src_hf)); + consoleOut(" Destination hash value = 0x%s\n", showHexHashValue_DG(resultDigest_dest_hf)); + + exit(1); + } + + if (resultDigest_src_mt != NULL && resultDigest_dest_mt != NULL && isEqual_DG(resultDigest_src_mt, resultDigest_dest_mt)) { + consoleOut("\nSUCCESS! same hashes - using Merkle hash tree:\n 0x%s\n", showHexHashValue_DG(resultDigest_src_mt)); + } + else { + consoleOut("\nFAILED! Different Merkle Tree hashes:\n"); + consoleOut(" Source hash value = 0x%s\n", showHexHashValue_DG(resultDigest_src_mt)); + consoleOut(" Destination hash value = 0x%s\n", showHexHashValue_DG(resultDigest_dest_mt)); + + exit(1); + } + } + + produceResults(); +} + + +//void localTest(); + +int main(int argc, char *argv[]) { + //localTest(); + processArgs(argc, argv); + runTest(); +} + + +/******************************************************************************* +// Deprecated/Test code + + + +static void processArgs(int argc, char *argv[]) { + char *argStr = NULL; + char rest[10]; + int val; + + double dbl; + + char code[1]; + + for (int i=1; i < argc; i++) { + argStr = argv[i]; + consoleOut("%i. %s", i, argStr); + + // Use a character to get option char +// if (sscanf(argStr, "-%c", code) > 0) { +// switch (code[0]) { +// case 'a': consoleOut("\tFOUND -f"); break; +// } +// } + + if (sscanf(argStr, "%i", &val) > 0) { + consoleOut("\tINT VALUE: %i", val); + } + + if (sscanf(argStr, "%lf", &dbl) > 0) { + consoleOut("\tDOUBLE VALUE: %lf", dbl); + } + + if (sscanf(argStr, "-%s", rest) > 0) { + consoleOut("\tARG: %s", rest); + } + + if (strncmp("-f", argStr, 2) == 0) { + consoleOut("\tstrcmp matched -f"); + } + + consoleOut("\n"); + } +} + + + + + +********************************************************************************/ diff --git a/hash_fusion/lib/alloc.c b/hash_fusion/lib/alloc.c new file mode 100644 index 0000000000..2cf6c20991 --- /dev/null +++ b/hash_fusion/lib/alloc.c @@ -0,0 +1,434 @@ +/******************************************************************************* + alloc.c + + Very simple free-list based storage management + + The implementation can be switched to a straightforward malloc/free + version (see USE_MALLOC_AND_FREE). + + Author: brian.monahan@hpe.com + + (c) Copyright 2017 Hewlett Packard Enterprise Development LP + + 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. + + 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. + +*******************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "utils.h" +#include "alloc.h" + +typedef struct pair Pair_t; + +struct memMgr { + size_t blockSize; // allocation size + + VoidFn_t initFn; // object initialiser function + VoidFn_t finalFn; // object finaliser function + + int allocated; // objects allocated + int length; // current length of allocation structure + + Pair_t *freeList; // allocation structure +}; + +struct pair { + void *object; // object pointer + Pair_t *nextItem; // next item +}; + + +// Global old cells list +// - Allows old pairs to be reused ... +static Pair_t *oldPairsList; + +// Global allocation structure for free-lists (!) +// - allows free-lists themselves to be allocated and deallocated. +static MemMgr_t *freeList_List = NULL; + + +// Static Method prototypes +static void ensureMemMgmt(void *obj); +static void dispose_MemMgr_Entries(MemMgr_t *fLst); + + +//////////////////////////////////////////////////////////////////////////////// +// Methods +//////////////////////////////////////////////////////////////////////////////// + +// creates a newly allocated allocation structure ... +MemMgr_t *new_MM(size_t blockSize) { + req_Pos(blockSize); + + // bootstrap allocation of allocation structures + if (freeList_List == NULL) { + // create freeList_List + freeList_List = ALLOC_OBJ(MemMgr_t); // Allocate MemMgr_t object + + ensureMemMgmt(freeList_List); // Initialise freeList_List + freeList_List->blockSize = sizeof(MemMgr_t); // set blockSize for MemMgr_t objects + + setInitialiser_MM(freeList_List, ensureMemMgmt); // set initialier for MemMgr_t objects + } + + // Allocate allocation structure ... + MemMgr_t *newList = allocateObject_MM(freeList_List); + newList->blockSize = blockSize; + + return newList; +} + + +// sets the object initialiser +// - this is run on all allocated objects ... +// either freshly created or reallocated. +void setInitialiser_MM(MemMgr_t *fLst, VoidFn_t initFn) { + req_NonNull(fLst); + + fLst->initFn = initFn; +} + + +// sets the object finaliser +// - this is run when allocation structures are disposed of. +void setFinaliser_MM(MemMgr_t *fLst, VoidFn_t finalFn) { + req_NonNull(fLst); + + fLst->finalFn = finalFn; +} + +// get length of allocation structure +int getLength_MM(MemMgr_t *fLst) { + req_NonNull(fLst); + + return fLst->length; +} + + +// get blockSize +size_t getBlockSize_MM(MemMgr_t *fLst) { + req_NonNull(fLst); + + return fLst->blockSize; +} + + +// get number of allocated objects +int getAllocated_MM(MemMgr_t *fLst) { + req_NonNull(fLst); + return fLst->allocated; +} + + +// Resets a allocation structure +// - disposes of allocation structure objects if the newBlockSize is different from current blocksize. +// - finaliser is run on all allocation structures elements. +void reset_MM(MemMgr_t *fLst, size_t newBlockSize) { + req_NonNull(fLst); + req_Pos(newBlockSize); + + // check if block size has changed ... + if (newBlockSize == fLst->blockSize) { + // no change needed to fLst object + return; + } + + // clears the current objects on allocation structure + dispose_MemMgr_Entries(fLst); + + // initialise allocation structure - as though it were freshly allocated + ensureMemMgmt(fLst); + + // sets the blocksize + fLst->blockSize = newBlockSize; +} + + +// recycles a allocation structure ... +void recycle_MM(MemMgr_t *obj) { + MemMgr_t *fLst = (MemMgr_t *)obj; + + // dispose of the allocation structure entries + // - this will activate the object finalisers ... + dispose_MemMgr_Entries(fLst); + + // recycle the MemMgr_t object on the freeList_List + deallocateObject_MM(freeList_List, sizeof(MemMgr_t), fLst); +} + + +/******************************************************************************* + Checking integrity +*******************************************************************************/ + +// Apply check on allocation +// - This check applies to all free-lists +Boolean_t checkAllocation_MM = FALSE; + +// Apply check on deallocation +// - This check applies to all free-lists +Boolean_t checkDeallocation_MM = FALSE; + +// Check allocation/deallocation integrity +// - checks if the given object is currently recycled ... +// - this is a hard error if so ... +Boolean_t checkIfRecycled_MM(MemMgr_t *fLst, void *obj) { + req_NonNull(fLst); + + Pair_t *nextPair = fLst->freeList; + + while (nextPair != NULL) { + if (nextPair->object == obj) { + return TRUE; + } + nextPair = nextPair->nextItem; + } + + return FALSE; +} + + +/******************************************************************************* + Static Methods +*******************************************************************************/ +static void ensureMemMgmt(void *obj) { + MemMgr_t *fLst = (MemMgr_t *)obj; + + //fLst->blockSize + fLst->initFn = NULL; + fLst->finalFn = NULL; + fLst->allocated = 0; + fLst->length = 0; + fLst->freeList = NULL; +} + + +static void dispose_MemMgr_Entries(MemMgr_t *fLst) { + req_NonNull(fLst); + + Pair_t* cells = fLst->freeList; // ensures that we only act upon an allocation structure ... + + if (cells == NULL) { + // Nothing to do ... + return; + } + + VoidFn_t finalFn = + (fLst->finalFn == NULL ? free : fLst->finalFn); + + Pair_t *curPair = cells; + Pair_t *prevPair = NULL; + + // move all cells to oldPairsList and reset any objects + while (curPair != NULL) { + // Make prevPair equal to the curPair. + prevPair = curPair; + + // Set curPair to the next cell pointed at by prevPair + curPair = prevPair->nextItem; + + // Finalise the object (if any) pointed at by prevPair; + finalFn(prevPair->object); + prevPair->object = NULL; + + // Add prevPair to oldPairsList + prevPair->nextItem = oldPairsList; + oldPairsList = prevPair; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// Allocation and Deallocation Methods +//////////////////////////////////////////////////////////////////////////////// + +#ifdef USE_MALLOC_AND_FREE + + + ///////////////////////////////////////////////////////////////////////////// + // Straightforward allocation using malloc/free + ///////////////////////////////////////////////////////////////////////////// + + // Allocates an object + // - runs the object initialiser function (if non-null). + void *allocateObject_MM(MemMgr_t *fLst) { + req_NonNull(fLst); + + // allocates fresh object memory + // - guaranteed to be zeroed (IMPORTANT!!) + void *resultObj = ALLOC_BLK(fLst->blockSize); + + fLst->allocated += 1; + + // run the object initialiser ... if initialiser function is non-null + if (fLst->initFn != NULL) { + fLst->initFn(resultObj); + } + + return resultObj; + } + + // Deallocates object by adding it to the allocation structure + // - the object is NOT finalised here ... only when allocation structures are disposed of/recycled. + // - the objSize parameter provides a simple check that the object is being returned + // to the correct memory pool. + void deallocateObject_MM(MemMgr_t *fLst, size_t objSize, void *obj) { + if (obj == NULL) return; + + req_NonNull(fLst); + req_EQ(objSize, fLst->blockSize); // heuristic integrity check that sizes are correct (not perfect) + + free(obj); + } + + +#else + + + ///////////////////////////////////////////////////////////////////////////// + // Allocation using allocation structures + ///////////////////////////////////////////////////////////////////////////// + + // Allocates an object (from allocation structure when possible) + // - runs the object initialiser function (if non-null). + void *allocateObject_MM(MemMgr_t *fLst) { + req_NonNull(fLst); + + void *resultObj = NULL; + + Pair_t *freePairs = fLst->freeList; + + if (freePairs == NULL) { + // allocates fresh object memory + // - guaranteed to be zeroed (IMPORTANT!!) + resultObj = ALLOC_BLK(fLst->blockSize); + + fLst->allocated += 1; + } + else { + + needs_Pos("length of allocation structure is not > 0", fLst->length); + + // take the top free cell from free cells + Pair_t *topPair = freePairs; + + // extract object from top cell.. + resultObj = topPair->object; + + // Ensure that the top cell releases object + topPair->object = NULL; + + // update allocation structure entry (i.e. remove topPair from allocation structure) + fLst->freeList = topPair->nextItem; + + // reduce length of allocation structure + fLst->length -= 1; + + // make topPair point at the current old cells list + topPair->nextItem = oldPairsList; + + // move top cell to the top of old cells list + oldPairsList = topPair; + } + + // run the object initialiser ... if initialiser function is non-null + if (fLst->initFn != NULL) { + fLst->initFn(resultObj); + } + + // check that allocated object is *not* curently deallocated ... + if (checkAllocation_MM) { + if (checkIfRecycled_MM(fLst, resultObj)) { + diagnostic("allocateObject_MM: Allocated object is currently deallocated: MemMgmt: 0x%lu, Object: 0x%lu" + , (Ptr_t)fLst + , (Ptr_t)resultObj + ); + error_exit(); + } + } + + return resultObj; + } + + + // Deallocates object by adding it to the allocation structure + // - the object is NOT finalised here ... only when allocation structures are + // disposed of/recycled. + // - the object may contain info such as associated memory pointers/sizes to + // be retained for reuse e.g. bytevectors. + // - the objSize parameter provides a heuristic check that the right kind of + // object is being returned into the correct memory pool. + void deallocateObject_MM(MemMgr_t *fLst, size_t objSize, void *obj) { + if (obj == NULL) return; + + req_NonNull(fLst); + req_EQ(objSize, fLst->blockSize); // heuristic integrity check that sizes are correct (not perfect) + + + // check that object is *not* already deallocated ... + if (checkDeallocation_MM) { + if (checkIfRecycled_MM(fLst, obj)) { + diagnostic("deallocateObject_MM: Attempted double deallocation of object: MemMgmt: 0x%lu, Object: 0x%lu" + , (Ptr_t)fLst + , (Ptr_t)obj + ); + error_exit(); + } + } + + Pair_t *freePairs = fLst->freeList; + + Pair_t *topPair = NULL; + + // ensure topPair exists ... + if (oldPairsList != NULL) { + // found existing pair + // take top pair from oldPairsList + topPair = oldPairsList; + + // make old pairs the next cell of top cell + oldPairsList = topPair->nextItem; + } + else { + // allocate fresh cell to top cell + topPair = ALLOC_OBJ(Pair_t); + } + + // Bind obj to topPair + topPair->object = obj; + + // make top cell link to free cells + topPair->nextItem = freePairs; + + // make allocation structure point at top cell + fLst->freeList = topPair; + + // increment length of allocation structure + fLst->length += 1; + } + +#endif diff --git a/hash_fusion/lib/alloc.h b/hash_fusion/lib/alloc.h new file mode 100644 index 0000000000..d96c78d1d8 --- /dev/null +++ b/hash_fusion/lib/alloc.h @@ -0,0 +1,113 @@ +#ifndef __ALLOC_H__ +#define __ALLOC_H__ + +#include "utils.h" + + +/******************************************************************************* + alloc.h + + Very basic memory management (using free-lists) + + The implementation can be switched to provide a straightforward malloc/free + version (see USE_MALLOC_AND_FREE) + + + (c) Copyright 2017 Hewlett Packard Enterprise Development LP + + 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. + + 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. + +*******************************************************************************/ + +// Uncomment the following line to use straightforward malloc/free allocation: +//#define USE_MALLOC_AND_FREE + +// Allocation structure structure +typedef struct memMgr MemMgr_t; + + +/******************************************************************************* + Methods +*******************************************************************************/ + +// creates a fresh allocation structure ... +MemMgr_t *new_MM(size_t blockSize); + + +// sets the object initialiser +void setInitialiser_MM(MemMgr_t *fLst, VoidFn_t initFn); + + +// sets the object finaliser +void setFinaliser_MM(MemMgr_t *fLst, VoidFn_t finalFn); + + +// get size of allocation structure +int getLength_MM(MemMgr_t *fLst); + + +// get number of allocated objects +int getAllocated_MM(MemMgr_t *fLst); + + +// get blockSize i.e. the size of memory to allocate +size_t getBlockSize_MM(MemMgr_t *fLst); + + +// allocates an object (from allocation structure if possible) +void *allocateObject_MM(MemMgr_t *fLst); + +// deallocates object +// - the objSize parameter is used to check that the object is being returned +// to the right memory pool. +void deallocateObject_MM(MemMgr_t *fLst, size_t objSize, void *obj); + +// Resets an allocation manager +// - disposes of allocation structure objects if the newBlockSize is different from current blocksize. +// - finaliser is run on all allocation structures elements. +void reset_MM(MemMgr_t *fLst, size_t newBlockSize); + + +// recycles a allocation structure ... +void recycle_MM(MemMgr_t *fLst); + + +/******************************************************************************* + Checking integrity +*******************************************************************************/ + +// Apply check on allocation +// - This check applies to all free-lists +Boolean_t checkAllocation_MM; + +// Apply check on deallocation +// - This check applies to all free-lists +Boolean_t checkDeallocation_MM; + +// Check allocation/deallocation integrity +// - checks if the given object is currently recycled ... +// - this is a hard error if so ... +Boolean_t checkIfRecycled_MM(MemMgr_t *fLst, void *obj); + +#endif diff --git a/hash_fusion/lib/arena.h b/hash_fusion/lib/arena.h new file mode 100644 index 0000000000..e6e5168ee8 --- /dev/null +++ b/hash_fusion/lib/arena.h @@ -0,0 +1,104 @@ +#ifndef __ARENA_H__ +#define __ARENA_H__ + +#include "utils.h" + + +/******************************************************************************* + arena.h + + Arena-based memory management + + An arena is a block of memory divided into a series of fixed-size blocks. + + Each block can have a reference count. Allocation is cheap. + + Memory is never physically deallocated - it means that it is unreserved. + This means that the memory is available for reallocation to an owner + for some use/purpose. The use of deallocated/unallocated memory is considered + erroneous until that memory is reallocated. + + The implementation can be switched to provide a straightforward malloc/free + version (see USE_MALLOC_AND_FREE_ARENA) + + Author: brian.monahan@hpe.com + + (c) Copyright 2017 Hewlett Packard Enterprise Development LP + + 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. + + 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. +*******************************************************************************/ + +// Uncomment the following line to use straightforward malloc/free allocation: +//#define USE_MALLOC_AND_FREE_ARENA + +// Arena Memory Manager +typedef struct arenaObj ArenaMemMgr_t; + +// Arena Allocation Policy +typedef enum { + REFERENCE_BLOCKS_POLICY_AMM, // blocks are objects - use reference counting. + TEMPORARY_BLOCKS_POLICY_AMM, // blocks represented temporary memory - ignore reference counting. + PERMANENT_BLOCKS_POLICY_AMM // blocks are permanent and are never recycled/deallocated - ignores reference counting. +} ArenaPolicy_t; + +// Allocates a new arena with blockSize, numBlocks and policy: +// - blockSize : size of block (i.e. allocation unit) +// - numBlocks : total number of blocks to be allocated. +// - policy : allocation policy to be used by arena. +ArenaMemMgr_t *new_AMM(int blockSize, int numBlocks, ArenaPolicy_t policy); + +// Deallocate the specified arena +// - This returns TRUE if deallocation was successful +// - If there are blocks still allocated, then deallocation of the arena +// will not succeed. +Boolean_t deallocateArena_AMM(ArenaMemMgr_t *arena); + +// Allocates the next block of memory ... +void *allocateBlock_AMM(ArenaMemMgr_t *arena); + +// Deallocates the given block of memory +// - Decrements the reference count (if this is meaningful) +void deallocateBlock_AMM(ArenaMemMgr_t *arena, void *block); + +// Get the arena allocation policy for arena +ArenaPolicy_t getPolicy_AMM(ArenaMemMgr_t *arena); + +// Get the size of blocks allocated by arena +int getBlockSize_AMM(ArenaMemMgr_t *arena); + +// Total number of blocks for arena: total = free + allocated +int getTotalBlocks_AMM(ArenaMemMgr_t *arena); + +// Number of blocks free for allocation by arena +int getFreeBlocks_AMM(ArenaMemMgr_t *arena); + +// Number of allocated blocks by arena +int getAllocatedBlocks_AMM(ArenaMemMgr_t *arena); + +// Increment reference to block (if possible) +// - This fails if the block was not allocated within the arena. +// +void incrRefCount_AMM(ArenaMemMgr_t *arena, void *block); + +#endif diff --git a/hash_fusion/lib/bytevector.c b/hash_fusion/lib/bytevector.c new file mode 100644 index 0000000000..c3a9d1ff4f --- /dev/null +++ b/hash_fusion/lib/bytevector.c @@ -0,0 +1,750 @@ +/******************************************************************************* + bytevector.c + + Basic bytevectors ... + - data length is always less than memory available (capacity), unless both are zero. + + The key invariant is: + (length == 0 && capacity == 0) || (0 <= length < capacity) + + Bytevectors support foreign data pointers; + - foreign data is treated as immutable. + - However, data content pointer can be exported + - This enables unmanaged data access/update of content. + + Bytevectors can be set to "append only" + - resetting will + + Bytevectors are allocated via free-list ... + + Author: brian.monahan@hpe.com + + (c) Copyright 2017 Hewlett Packard Enterprise Development LP + + 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. + + 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. +*******************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "utils.h" +#include "alloc.h" +#include "random.h" + +#include "bytevector.h" + + +// The bytevector structure ... +struct bytevector { + int capacity; // amount of memory available. + size_t length; // extent of data in use. + Boolean_t appendOnly; // indicates append-only. + Boolean_t isForeign; // indicates if pointer is foreign (if so, then the data is internally immutable.) + Byte_t *content; // content pointer +}; + + +// Bytevector Memory Management +MemMgr_t *bytevecMemMgmt = NULL; + + +// static method prototypes +static void ensureMemMgmt(); +static void dispose_BV(void *obj); +static void addContent(ByteVec_t *vec, int dataLen, Byte_t *data); + + +// Allocates a standard size bytevector (with default capacity) +ByteVec_t *new_BV() { + return allocate_BV(DEFAULT_BYTEVECTOR_CAPACITY); +} + +// Allocates a bytevector of specified capacity +// - Setting zero capacity does not allocate any storage. +ByteVec_t *allocate_BV(int capacity) { + + // ensure the allocation structure is initialised + ensureMemMgmt(); + + // Gets allocated result ... + ByteVec_t *result = allocateObject_MM(bytevecMemMgmt); + + if (result->capacity == 0) { + // allocated object has no attached content memory ... + // - this is also the case if the object were freshly allocated and not recycled. + if (capacity == 0) { + // empty bytevector + // - no storage allocated ... + result->capacity = 0; + result->length = 0; + result->appendOnly = FALSE; + result->isForeign = FALSE; + result->content = NULL; + } + else { + // non-empty bytevector - of zero length + result->capacity = capacity; + result->length = 0; + result->appendOnly = FALSE; + result->isForeign = FALSE; + result->content = ALLOC_BLK(result->capacity); // guaranteed zero'd + } + } + else { + // allocated result has attached memory ... (i.e. recycled) + // - attached memory was scrubbed at deallocation time + ensureCapacity_BV(result, capacity); + + // set attributes + result->capacity = capacity; + result->length = 0; + result->appendOnly = FALSE; + result->isForeign = FALSE; + } + + return result; +} + + +// Deallocates bytevector +// - if the given bytevector contains foreign data, this returns the data content pointer. +// - Otherwise, returns NULL. +// - the bytevector is recycled (with attached memory already zeroed) for reuse. +Byte_t *deallocate_BV(ByteVec_t *vec) { + if (vec == NULL) { + return NULL; + } + + Byte_t *result = NULL; + + if (vec->isForeign) { + // export the content + result = vec->content; + + // decouple foreign content from bytevector + vec->capacity = 0; + vec->content = NULL; + } + else if (vec->capacity > 0) { + // scrub the attached memory ... + NULLIFY(vec->content, vec->capacity); + } + + // reset the object + vec->length = 0; + vec->appendOnly = FALSE; + vec->isForeign = FALSE; + + // ensure the allocation structure is initialised + ensureMemMgmt(); + + // Now recycle the bytevector itself + // - by adding it to the bytevector allocation structure ... + deallocateObject_MM(bytevecMemMgmt, sizeof(ByteVec_t), (void *)vec); + + return result; +} + + +// Resets the given bytevector to empty state (i.e. zero length) +// - does not remove non-foreign allocated memory - instead this is zeroed. +// - if bytevector contains foreign data, then the pointer is returned, +// and the state of the bytevector is reset to non-foreign. +// - resets the appendOnly attribute to FALSE +Byte_t *reset_BV(ByteVec_t *vec) { + req_NonNull(vec); + + // this is used to report any foreign pointer ... + Byte_t *foreignPtr = NULL; + + // sets the length to zero ... + vec->length = 0; + + // always set the appendOnly attribute to false + // - if append only semantics is required, this must be set again + // following any reset. + vec->appendOnly = FALSE; + + // Process foreign vectors + if (vec->isForeign) { + // return foreign content pointer + foreignPtr = vec->content; + + // Now set vec to empty + vec->capacity = 0; // no capacity + vec->isForeign = FALSE; // vec is no longer foreign + vec->content = NULL; // no memory + } + else if (vec->capacity > 0) { + // fill content with zero ... + NULLIFY(vec->content, vec->capacity); + } + + // return any foreign pointer + return foreignPtr; +} + +// synonym for reset_BV ... +Byte_t *wipe_BV(ByteVec_t *vec) { + return reset_BV(vec); +} + + +int getCapacity_BV(ByteVec_t *vec) { + req_NonNull(vec); + return vec->capacity; +} + + +size_t getLength_BV(ByteVec_t *vec) { + req_NonNull(vec); + return vec->length; +} + +void setLength_BV(ByteVec_t *vec, size_t length) { + req_NonNull(vec); + + if (vec->isForeign) { + // For foreign data, assert the capacity according to given length. + vec->capacity = length +1; + } + else if (vec->appendOnly && length < vec->length) { + diagnostic("setLength_BV: Bytevector is set to append only - cannot reduce length from %i to smaller length %i" + , length + , vec->length); + error_exit(); + } + else if (vec->capacity <= length) { + diagnostic("setLength_BV: new length (%i) exceeds or equals capacity (%i)", length, vec->capacity); + error_exit(); + } + + vec->length = length; +} + + +// sets the bytevector to be append only +// - once set, this attribute can only be removed by resetting the entire byte vector using reset_BV +void setAppendOnly_BV(ByteVec_t *vec) { + req_NonNull(vec); + + vec->appendOnly = TRUE; +} + + +Boolean_t isEmpty_BV(ByteVec_t *vec) { + req_NonNull(vec); + + return (vec->length == 0 || vec->content == NULL); +} + + +Byte_t *getContent_BV(ByteVec_t *vec) { + req_NonNull(vec); + + return vec->content; +} + + +Boolean_t hasForeignData_BV(ByteVec_t *vec) { + req_NonNull(vec); + return vec->isForeign; +} + + +// Imports existing data (i.e. foreign pointer); +// - This data is regarded as fixed and unmodifiable. +// - As a consequence, bytevectors containing foreign data are not extendable and +// cannot be wiped or updated. +void importForeignContent_BV(ByteVec_t *vec, int dataLen, Byte_t *foreignData) { + req_NonNull(vec); + + if (vec->isForeign) { + diagnostic("bytevector.importForeignContent_BV: Bytevector already contains foreign data - and cannot be extended."); + codeError_exit(); + } + + if (foreignData == NULL && dataLen > 0) { + diagnostic("bytevector.importForeignContent_BV: Inconsistent content assignment (content = NULL, but length > 0)"); + codeError_exit(); + } + + // release any existing data + free(vec->content); + + // update bytevector's attributes + vec->length = dataLen; + vec->capacity = dataLen + 1; + vec->isForeign = TRUE; + vec->content = foreignData; +} + + +// loads indicated content into byte vector +// - sets bytes from data array +// - uses existing data memory in bytevector where possible, +// - otherwise, extends memory to contain additional content +void setContent_BV(ByteVec_t *vec, int dataLen, Byte_t *data) { + req_NonNull(vec); + + if (vec->isForeign) { + diagnostic("bytevector.setContent_BV: Bytevector contains foreign data - and cannot be extended."); + codeError_exit(); + } + + if (data == NULL && dataLen > 0) { + diagnostic("bytevector.setContent_BV: Inconsistent content assignment (content = NULL, but length > 0)"); + codeError_exit(); + } + + if (vec->appendOnly) { + diagnostic("bytevector.setContent_BV: Bytevector set to append only - cannot set the content arbitrarily."); + codeError_exit(); + } + + // reset te bytevector ... + // - ensures that previous data gets zero'ed. + reset_BV(vec); + + // now add the content ... + addContent(vec, dataLen, data); +} + +// appends indicated content into byte vector +// - appends bytes from data array to end of bytevector +// - uses existing data memory in bytevector where possible, +// - otherwise, extends memory to contain additional content +void appendContent_BV(ByteVec_t *vec, int dataLen, Byte_t *data) { + req_NonNull(vec); + + if (vec->isForeign) { + diagnostic("bytevector.appendContent_BV: Bytevector contains foreign data - and cannot be extended."); + codeError_exit(); + } + + if (data == NULL && dataLen > 0) { + diagnostic("bytevector.appendContent_BV: Inconsistent content assignment (content = NULL, but length > 0)"); + codeError_exit(); + } + + // now add the content ... + addContent(vec, dataLen, data); +} + + +// Internal operation to add data +static void addContent(ByteVec_t *vec, int dataLen, Byte_t *data) { + + int vecDataLen = vec->length; // current data length + int newDataLen = vecDataLen + dataLen; // updated data length + + if (newDataLen >= vec->capacity) { + ensureCapacity_BV(vec, newDataLen+1); // guarantees that newDataLen < new capacity of vec + } + + // copy any new data into vector + if (dataLen > 0) { + memcpy(vec->content + vecDataLen, data, dataLen); + } + + // record new data length. + vec->length = newDataLen; + + // ensures that sentinel byte is 0 (i.e. safe for C-strings) + vec->content[newDataLen] = 0; +} + + +void ensureCapacity_BV(ByteVec_t *vec, int capacity) { + + req_NonNull(vec); + req_PosZero(capacity); + + // return if capacity requested is zero ... + if (capacity == 0) return; + + if (vec->isForeign) { + diagnostic("bytevector.ensureCapacity_BV: Bytevector contains foreign data - and cannot be extended."); + codeError_exit(); + } + + int vecCapacity = vec->capacity; + Byte_t *vecContent = vec->content; + size_t vecLength = vec->length; + + // check if extra capacity needed ... + if (capacity <= vecCapacity) { + return; + } + + // needs some extra memory ... + int newCapacity = capacity + vecCapacity; + Byte_t *newContent = (Byte_t *)ALLOC_BLK(newCapacity); + //Byte_t *newContent = (Byte_t *)REALLOC_BLK(vecContent, newCapacity); // using this caused data corruption to vec->length (!!) + + if (vecLength > 0) { + // copying previous content into new memory ... + memcpy(newContent, vecContent, vecLength); + } + + // update vec ... + vec->capacity = newCapacity; + vec->content = newContent; + vec->length = vecLength; + + // free previous memory + free(vecContent); +} + + +// Clones source bytevector into given destination vector. +// - copies content from source to destination +// - both vectors must already exist. +// - destination must not already contain foreign data. +void clone_BV(ByteVec_t *dest, ByteVec_t *source) { + req_NonNull(dest); + req_NonNull(source); + + if (dest->isForeign) { + diagnostic("bytevector.clone_BV: Destination bytevector contains foreign data - and cannot be modified/extended."); + codeError_exit(); + } + + int dataLen = source->length; + + // ensure sufficient capacity to contain the data in the source. + ensureCapacity_BV(dest, dataLen+1); + + if (dataLen > 0) { + // copy source data into the destination ... + memcpy(dest->content, source->content, dataLen); + } + + // update the length of the destination ... + dest->length = dataLen; +} + + +// Checks that the bytevectors are equal in _value_ (on content) ... +// - Both must be equally defined i.e. both = NULL or both != NULL +// - byte comparison of content up to length +Boolean_t isEqual_BV(ByteVec_t *vec1, ByteVec_t *vec2) { + if (vec1 == NULL) { + return (vec2 == NULL); + } + else if (vec2 == NULL) { + // i.e. vec1 != NULL and vec2 == NULL + return FALSE; + } + + // Know here that: vec1 != NULL and vec2 != NULL + + // check length of content + int vecLen1 = vec1->length; + int vecLen2 = vec2->length; + + if (vecLen1 != vecLen2) { + // vec1 and vec2 have different lengths + return FALSE; + } + + // compare memory + return asBoolean(memcmp(vec1->content, vec2->content, vecLen1) == 0); +} + + +// Generate a randomised bytevector of specified length +void random_BV(ByteVec_t *vec, int dataLen) { + req_NonNull(vec); + req_PosZero(dataLen); + + // check for foreign data + if (vec->isForeign) { + diagnostic("bytevector.random_BV: Destination bytevector contains foreign data - and cannot be modified."); + codeError_exit(); + } + + // ensure the capacity ... + ensureCapacity_BV(vec, dataLen+1); + + Byte_t *arr = vec->content; + for (int i = 0; i < dataLen; i++) { + arr[i] = nextRandom_BYTE(); + } + + // set the length + vec->length = dataLen; +} + + +Byte_t getByte_BV(ByteVec_t *vec, int i) { + req_NonNull(vec); + req_NonNull(vec->content); + + req_LE(0, i); + req_LT(i, vec->length); + + return (vec->content)[i]; +} + + +void setByte_BV(ByteVec_t *vec, int idx, Byte_t newVal) { + req_NonNull(vec); + req_LE(0, idx); + + if (vec->isForeign) { + diagnostic("bytevector.setByte_BV: Bytevector contains foreign data - and cannot be modified."); + codeError_exit(); + } + + if (vec->appendOnly) { + diagnostic("bytevector.setByte_BV: Bytevector set to append only - no arbitrart modification."); + codeError_exit(); + } + + // check if update requires memory expansion. + if (vec->length <= idx) { + int newLength = idx+1; + int newCapacity = newLength+1; + ensureCapacity_BV(vec, newCapacity); // expand memory to include index ... + vec->length = newLength; // make length = one greater than index + } + + // sets content at index to newVal + (vec->content)[idx] = newVal; +} + + +// Joins two bytevectors together as a new, freshly allocated bytevector. +ByteVec_t *join_BV(ByteVec_t *a, ByteVec_t *b) { + req_NonNull(a); + req_NonNull(b); + + int aDataLen = a->length; + int bDataLen = b->length; + + int newDataLen = aDataLen + bDataLen; + int newCapacity = newDataLen + 1; + + ByteVec_t *result = allocate_BV(newCapacity); + + Byte_t *data = result->content; + + // copy the data ... + if (aDataLen > 0) { + memcpy(data, a->content, aDataLen); + } + + if (bDataLen > 0) { + memcpy(data+aDataLen, b->content, bDataLen); + } + + // update the length of the result ... + result->length = newDataLen; + + return result; +} + + +void joinInto_BV(ByteVec_t *dest, ByteVec_t *a, ByteVec_t *b) { + req_NonNull(a); + req_NonNull(b); + req_Distinct(a, dest); + req_Distinct(b, dest); + req_NonNull(dest); + + // clear the existing content in dest + wipe_BV(dest); + + appendContent_BV(dest, a->length, a->content); + appendContent_BV(dest, b->length, b->content); +} + + +void appendInto_BV(ByteVec_t *dest, ByteVec_t *source) { + + req_NonNull(source); + req_NonNull(dest); + req_Distinct(source, dest); + + if (dest->isForeign) { + diagnostic("bytevector.appendInto_BV: Destination bytevector contains foreign data - and cannot be modified."); + codeError_exit(); + } + + appendContent_BV(dest, source->length, source->content); +} + + +/******************************************************************************* + Fingerprinting +*******************************************************************************/ +// Extracts a short fingerprint of the bytevector +// - the output string is volatile +// - 4 <= fpLength <= 16, with default value: 7 +static char fpBuf[LINE_BUFSIZE+1]; +static int DEFAULT_FP_LENGTH = 7; +char *showFingerprint_BV(ByteVec_t *vec, int fpLength) { + if (vec == NULL) return NULL_STR; + + char *sPtr = fpBuf; + Byte_t *bytes = vec->content; + + if (bytes == NULL) return NULL_STR; + + // constrain the fpLength + fpLength = (fpLength <= 0 ? DEFAULT_FP_LENGTH : fpLength); + fpLength = minmax(4, fpLength, 16); + fpLength = min(fpLength, vec->length); + + // pack content as hex into hashBuffer + int sz = 0; + char *sep = ""; + for(int i = 0; i < fpLength; i++) { + sz = sprintf(sPtr, "%s%02x", sep, bytes[i]); + sPtr += sz; + sep = ":"; + } + + sprintf(sPtr, " ... [%lu bytes]", vec->length); + + return fpBuf; +} + + +/******************************************************************************* + Show methods +*******************************************************************************/ +static ByteVec_t *showBuffer = NULL; + +// local prototypes +static char *auxShow_BV(ByteVec_t *vec, const char *fmt, int width, char *indent); + + +// Show bytevector +// - uses decimal repn. +char *show_BV(ByteVec_t *vec, int width, char *indent) { + return auxShow_BV(vec, "%3i ", width, indent); +} + +// Show bytevector +// - uses hex repn. +char *showHex_BV(ByteVec_t *vec, int width, char *indent) { + return auxShow_BV(vec, "%02x ", width, indent); +} + + +static char *auxShow_BV(ByteVec_t *vec, const char *fmt, int width, char *indent) { + req_NonNull(vec); + req_NonEmptyStr((char *)fmt); + + // ensure that indent is a string ... + indent = (isa_Null(indent) ? " " : indent); + + // ensure that width is at least 5 items wide + width = max(width, 5); + + // current byte + Byte_t curByte = 0; + + // lengths + int indentLen = strlen(indent); + int vecLen = vec->length; + + // display characteristics + int linecount = 0; + int widthcount = 0; + + // local string buffer + char strBuf[17]; // fmt must define strings that are less than 16 chars in width + int bufSz = 0; // number of chars in strBuf + + // initialise showBuffer + if (showBuffer == NULL) { + int allocation = max(DEFAULT_BYTEVECTOR_CAPACITY, 10 * (vec->length)); + showBuffer = allocate_BV(allocation); + } + else { + reset_BV(showBuffer); + } + + // add content to showBuffer + // - this will automatically extend as needed ... + for (int i=0; i < vecLen; i++) { + if (widthcount == 0) { + appendContent_BV(showBuffer, indentLen, (Byte_t *)indent); + } + + curByte = getByte_BV(vec, i); + bufSz = sprintf(strBuf, fmt, curByte); + + // add content to showBuffer + appendContent_BV(showBuffer, bufSz, (Byte_t *)strBuf); + + widthcount += 1; + if (widthcount >= width) { + widthcount = 0; + linecount += 1; + appendContent_BV(showBuffer, 1, (Byte_t *)"\n"); + + if (linecount >= 10) { + appendContent_BV(showBuffer, 1, (Byte_t *)"\n"); + } + } + } + + if (widthcount != 0) { + // add a newline to terminate current line + appendContent_BV(showBuffer, 1, (Byte_t *)"\n"); + } + + return (char *)showBuffer->content; +} + + +/******************************************************************************* + Static Methods +*******************************************************************************/ + +// Initialisation of allocation structure +static void ensureMemMgmt() { + if (bytevecMemMgmt == NULL) { + bytevecMemMgmt = new_MM(sizeof(ByteVec_t)); + setFinaliser_MM(bytevecMemMgmt, dispose_BV); + } +} + +// Disposal of bytevector object ... +static void dispose_BV(void *obj) { + if (obj == NULL) return; + + ByteVec_t *vec = (ByteVec_t *)obj; + + // First free the content ... + free(vec->content); + + // Now free the bytevector structure itself ... + free(vec); +} diff --git a/hash_fusion/lib/bytevector.h b/hash_fusion/lib/bytevector.h new file mode 100644 index 0000000000..455979b581 --- /dev/null +++ b/hash_fusion/lib/bytevector.h @@ -0,0 +1,197 @@ +#ifndef __BYTEVECTOR_H__ +#define __BYTEVECTOR_H__ + +#include "utils.h" + + +/******************************************************************************* + bytevector.h + + Basic bytevectors ... + + Author: brian.monahan@hpe.com + + (c) Copyright 2017 Hewlett Packard Enterprise Development LP + + 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. + + 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. + +*******************************************************************************/ + +typedef struct bytevector ByteVec_t; + +#define DEFAULT_BYTEVECTOR_CAPACITY 16 + + +// Allocates a standard size bytevector (with default capacity) +// - uses the default bytevector capacity as initial capacity +// - use ensureCapacity_BV to explicitly extend bytevector capacity. +ByteVec_t *new_BV(); + + +// Allocates a bytevector of specified capacity +// - Setting zero capacity does not allocate any storage. +ByteVec_t *allocate_BV(int capacity); + + +// Deallocates bytevector +// - if the given bytevector contains foreign data, this returns the data pointer. +// - Otherwise, returns NULL. +// - the bytevector is recycled (with attached zeroed memory) into a allocation structure. +Byte_t *deallocate_BV(ByteVec_t *vec); + + +// Resets the given bytevector to empty state (i.e. zero length) +// - does not remove non-foreign allocated memory - instead this is zeroed. +// - if bytevector contains foreign data, then the pointer is returned, +// and the state of the bytevector is reset to non-foreign. +// - resets the appendOnly attribute to FALSE +Byte_t *reset_BV(ByteVec_t *vec); +Byte_t *wipe_BV(ByteVec_t *vec); // synonym for reset_BV + + +// gets the memory size allocated +int getCapacity_BV(ByteVec_t *vec); + + +// gets the data length (always less than the memory size) +size_t getLength_BV(ByteVec_t *vec); + + +// sets the data length +// - must remain strictly less than the capacity. +// - if bytevector is set append only, then length cannot be decreased. +void setLength_BV(ByteVec_t *vec, size_t length); + + +// sets the bytevector to be append only +// - once set, this attribute can only be removed by resetting the entire byte vector +void setAppendOnly_BV(ByteVec_t *vec); + + +// ensures that memory capacity equals or exceeds the given value. +// - if current capacity already equals or exceeds given value then no change. +// - extension involves reallocating memory. +void ensureCapacity_BV(ByteVec_t *vec, int capacity); + + +// indicates if given bytevector is "empty" ... +// - i.e. doesn't contain data. +Boolean_t isEmpty_BV(ByteVec_t *vec); + + +// exports pointer to internal data vector +// - this permits the memory to be manipulated externally (UNSAFE). +// - the external pointer returned can become stale due to further +// extension of the bytevector. +// - use setLength to update the length ... +Byte_t *getContent_BV(ByteVec_t *vec); + + +// Clones source bytevector into given destination vector. +// - copies content from source to destination +// - both vectors must already exist. +// - destination must not already contain foreign data. +void clone_BV(ByteVec_t *dest, ByteVec_t *source); + + +// Checks that the bytevectors are equal in _value_ (on content) ... +// - Both must be equally defined i.e. both = NULL or both != NULL +// - byte comparison of content up to length +Boolean_t isEqual_BV(ByteVec_t *vec1, ByteVec_t *vec2); + + +// indicates if givne bytevector contains foreign data. +// - The bytevector cannot be modified or changed once it contains foreign data. +Boolean_t hasForeignData_BV(ByteVec_t *vec); + + +// Imports existing data (i.e. foreign pointer); +// - This data is regarded as fixed and unmodifiable. +// - As a consequence, bytevectors containing foreign data are not extendable and +// cannot be wiped or updated. +void importForeignContent_BV(ByteVec_t *vec, int dataLen, Byte_t *data); + + +// loads indicated content into byte vector +// - sets bytes from data array +// - uses existing data memory in bytevector where possible, +// - otherwise, extends memory to contain additional content +void setContent_BV(ByteVec_t *vec, int dataLen, Byte_t *data); + + +// appends indicated content into byte vector +// - appends bytes from data array to end of bytevector +// - uses existing data memory in bytevector where possible, +// - otherwise, extends memory to contain additional content +void appendContent_BV(ByteVec_t *vec, int dataLen, Byte_t *data); + + +// Generate a randomised bytevector of specified length +void random_BV(ByteVec_t *vec, int dataLen); + + +// gets current value at given index idx +// - idx always less than current data length +Byte_t getByte_BV(ByteVec_t *vec, int idx); + + +// sets current value at given index idx +// - setting values can force memory extension. +void setByte_BV(ByteVec_t *vec, int idx, Byte_t newVal); + + +// Joins two bytevectors together as a new, freshly allocated bytevector. +ByteVec_t *join_BV(ByteVec_t *a, ByteVec_t *b); + + +// Joins content from two bytevectors a and b into dest bytevector +// - Uses the already allocated memory in dest. +// - Will enlarge allocated memory of dest to ensure sufficient memory ... +// - Dest bytevector must be distinct from given sources +void joinInto_BV(ByteVec_t *dest, ByteVec_t *a, ByteVec_t *b); + + +// Appends content from source bytevector into dest bytevector +// - Uses already allocated memory in dest +// - Will enlarge allocated memory of dest to ensure sufficient memory ... +void appendInto_BV(ByteVec_t *dest, ByteVec_t *source); + + +// Shows a short hex fingerprint of the bytevector +// - the output string is volatile +// - 4 <= fpLength <= 16, with default value: 7 +char *showFingerprint_BV(ByteVec_t *vec, int fpLength); + + +// Show bytevector content +// - uses decimal repn. +char *show_BV(ByteVec_t *vec, int width, char *indent); + + +// Show bytevector content +// - uses hex repn. +char *showHex_BV(ByteVec_t *vec, int width, char *indent); + + +#endif diff --git a/hash_fusion/lib/debug.h b/hash_fusion/lib/debug.h new file mode 100644 index 0000000000..c675a7e3ba --- /dev/null +++ b/hash_fusion/lib/debug.h @@ -0,0 +1,54 @@ +#ifndef __DEBUG_H__ +#define __DEBUG_H__ + +/******************************************************************************* + debug.h + + Debugging using print statements/testing... + + Including this file enables debugging ... + + Author: brian.monahan@hpe.com + + (c) Copyright 2017 Hewlett Packard Enterprise Development LP + + 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. + + 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. +*******************************************************************************/ + +#undef debug +#undef xdebug + +#undef DEBUG_CODE +#undef XDEBUG_CODE + +#define debug __DEBUG +#define xdebug __XDEBUG + +#define DEBUG_CODE + +#ifndef DEBUG_LIMIT + #define DEBUG_LIMIT 1000 +#endif + +#endif diff --git a/hash_fusion/lib/exptLib.c b/hash_fusion/lib/exptLib.c new file mode 100644 index 0000000000..020a39fe43 --- /dev/null +++ b/hash_fusion/lib/exptLib.c @@ -0,0 +1,188 @@ +/******************************************************************************* + exptLib.c + + Experimental management framework utilities + + - Managing key identifiers (numbers) + + - Managing values + + Author: brian.monahan@hpe.com + + (c) Copyright 2017 Hewlett Packard Enterprise Development LP + + 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. + + 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. +*******************************************************************************/ + +#include "exptLib.h" +#include "random.h" + + +/******************************************************************************* + Variables and Arrays +*******************************************************************************/ + +static Boolean_t seenKey[MAX_KEY_VALUE]; // 0 .. MAX_KEY_VALUE - with valid keys being 1 .. MAX_KEY_VALUE +static Key_t keyIndex[MAX_KEYS]; + +// Invariant: availKeys + numKeys == MAX_KEYS +static int availKeys = MAX_KEYS; // 1 .. MAX_KEYS -- number of available keys +static int numKeys = 0; // number of keys in use + +// object map +static void *objIndex[MAX_KEY_VALUE]; // Object mapping + + +/******************************************************************************* + Methods +*******************************************************************************/ + +// generate new key +Key_t freshKey() { + if (availKeys <= 0) return NULL_KEY; + + int possKey = nextRandom_Range(1, MAX_KEY_VALUE); + + int key = 0; + + // scan keys to find the next available + for (int i=1; i <= MAX_KEY_VALUE; i++) { + if (!seenKey[possKey]) { + key = possKey; + + registerKey(key); + + return key; + } + + // increment possKey + possKey += 1; + if (possKey > MAX_KEY_VALUE) possKey = 1; + } + + return NULL_KEY; +} + + +// gets a randomly selected registered key - and then unregistering it from the key index +Key_t getKey() { + + if (numKeys <= 0) return NULL_KEY; + + int index = nextRandom_Range(0, numKeys-1); + + Key_t key = keyIndex[index]; + + seenKey[key] = FALSE; + + if (numKeys > 0) { + + numKeys -= 1; + availKeys += 1; + + keyIndex[index] = keyIndex[numKeys]; + keyIndex[numKeys] = NULL_KEY; + } + else { + numKeys = 0; + availKeys = MAX_KEYS; + } + + return key; +} + + +// Add value to the store +void addValue(Key_t key, void *value) { + if (key < 1 || key > MAX_KEY_VALUE) return; + + objIndex[key] = value; +} + + +// checks if key currently allocated/in use +Boolean_t allocatedKey(Key_t key) { + if (key < 1 || key > MAX_KEY_VALUE) return FALSE; + return seenKey[key]; +} + + +// Fetch associated value ... +void *fetchValue(Key_t key) { + if (key < 1 || key > MAX_KEY_VALUE) return NULL; + return objIndex[key]; +} + + +// Registers a key as being in use ... +// - return TRUE if registration was OK. +Boolean_t registerKey(Key_t key) { + if (availKeys <= 0) return FALSE; + if (key < 1 || key > MAX_KEY_VALUE) return FALSE; + if (seenKey[key]) return FALSE; + + // selecting key + seenKey[key] = TRUE; + keyIndex[numKeys] = key; + + availKeys -= 1; + numKeys += 1; + + return TRUE; +} + + +// Unregisters a key as being in use ... +// - return TRUE if deregistration was OK. +Boolean_t unregisterKey(Key_t key) { + if (numKeys < 1) return FALSE; + if (key < 1 || key > MAX_KEY_VALUE) return FALSE; + if (!seenKey[key]) return FALSE; + + // deselecting key + availKeys += 1; // increase number of keys + numKeys -= 1; // decrease the number of used keys + + Key_t lastKey = keyIndex[numKeys]; + + // mark key as not seen + seenKey[key] = FALSE; + + // locate index for key ... + int index = 0; + while (keyIndex[index] != key) { + index += 1; + if (index >= MAX_KEYS) return TRUE; + } + + keyIndex[index] = lastKey; + keyIndex[numKeys] = NULL_KEY; + + return TRUE; +} + + +int getKeysInUse() { + return numKeys; +} diff --git a/hash_fusion/lib/exptLib.h b/hash_fusion/lib/exptLib.h new file mode 100644 index 0000000000..918c526503 --- /dev/null +++ b/hash_fusion/lib/exptLib.h @@ -0,0 +1,77 @@ +#ifndef __EXPT_LIB_H__ +#define __EXPT_LIB_H__ + +#include "utils.h" + + +/******************************************************************************* + exptLib.h + + Experimental framework + + - Managing key identifiers (as numbers) + + Author: brian.monahan@hpe.com + + (c) Copyright 2017 Hewlett Packard Enterprise Development LP + + 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. + + 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. + +*******************************************************************************/ + +#define MAX_KEYS 10000 +#define MAX_KEY_VALUE 100000 + + +/******************************************************************************* + Key Management Methods +*******************************************************************************/ + +// Generate a fresh randomly generated key +Key_t freshKey(); + +// Add value to the store +void addValue(Key_t key, void *value); + +// Checks if key currently allocated/in use +Boolean_t allocatedKey(Key_t key); + +// Gets a randomly selected registered key - and then unregisters it from the key index +Key_t getKey(); + +// Fetch associated value ... +void *fetchValue(Key_t key); + +// Registers a key as being in use ... +// - return TRUE if registration was OK. +Boolean_t registerKey(Key_t key); + +// Unregisters a key as being in use ... +// - return TRUE if deregistration was OK. +Boolean_t unregisterKey(Key_t key); + +// Number of keys in use +int getKeysInUse(); + +#endif diff --git a/hash_fusion/lib/fragment.c b/hash_fusion/lib/fragment.c new file mode 100644 index 0000000000..0c618b9571 --- /dev/null +++ b/hash_fusion/lib/fragment.c @@ -0,0 +1,323 @@ +/******************************************************************************* + fragment.c + + Implements fragment classes and objects. + + These structures are transparently implemented - with open access/update. + + Uses opaque objects to encode generics ... + + Author: brian.monahan@hpe.com + + (c) Copyright 2017 Hewlett Packard Enterprise Development LP + + 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. + + 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. +*******************************************************************************/ + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "utils.h" +#include "alloc.h" +#include "fragment.h" + +/******************************************************************************* + Memory Management +*******************************************************************************/ +static MemMgr_t *fragCls_MemMgr = NULL; +static MemMgr_t *fragObj_MemMgr = NULL; + + +/******************************************************************************* + Static Method prototypes +*******************************************************************************/ +// Memory management helper +static void ensureMemMgmt(); + +static FragCompare_t + fragmentCompare(CompareFn_t posnCompFn, + Posn_t thisLower, + Posn_t thisUpper, + Posn_t otherLower, + Posn_t otherUpper); + + +/******************************************************************************* + Fragment Class Methods +*******************************************************************************/ +// +// Create a new fragment system class (FragCls_t) +// - This provides a coordinated set of related methods: +// +// - Parametric methods: +// posnCompFn : positionPos comparison function +// adjCompFn : adjacency comparison function +// objCombFn : object combination function +// finalObjFn : finalise object function +FragCls_t *new_FC(CompareFn_t posnCompFn, AdjCompareFn_t adjCompFn, CombineFn_t objCombFn, VoidFn_t finalObjFn) { + + // ensure that the allocation structures exist ... + ensureMemMgmt(); + + // check integrity + if (posnCompFn == NULL) { + diagnostic("new_FC : Null position comparison function given"); + error_exit(); + } + + if (adjCompFn == NULL) { + diagnostic("new_FC : Null adjacency comparison function given"); + error_exit(); + } + + if (objCombFn == NULL) { + diagnostic("new_FC : Null object combination function given"); + error_exit(); + } + + // defaults + finalObjFn = (finalObjFn == NULL ? nullVoidFn : finalObjFn); + + // allocate new class + FragCls_t *newCls = allocateObject_MM(fragCls_MemMgr); + + // set attributes + newCls->posnCompFn = posnCompFn; + newCls->adjCompFn = adjCompFn; + newCls->objCombFn = objCombFn; + newCls->finalObjFn = finalObjFn; + + return newCls; +} + + +// Deallocate fragment class +void deallocate_FC(void *item) { + if (item == NULL) return; + + // ensure that the allocation structures exist ... + ensureMemMgmt(); + + FragCls_t *fragCls = (FragCls_t *)item; + + // Nullify object + NULLIFY_OBJ(fragCls, FragCls_t) + + // recycle the current fragment object + deallocateObject_MM(fragCls_MemMgr, sizeof(FragCls_t), fragCls); +} + + +// Clones object +FragCls_t *clone_FC(FragCls_t *fragCls) { + return new_FC(fragCls->posnCompFn, fragCls->adjCompFn, fragCls->objCombFn, fragCls->finalObjFn); +} + + +/******************************************************************************* + Fragment Object Methods +*******************************************************************************/ +// Create a new fragment + value objects +// - note that fragCls should be non-null. +Frag_t *new_Frag(FragCls_t *fragCls, Posn_t lower, Posn_t upper, Object_t value) { + req_NonNull(fragCls); + + // ensure that the allocation structures exist ... + ensureMemMgmt(); + + // allocate new Tree + Frag_t *newObj = allocateObject_MM(fragObj_MemMgr); + + // set attributes + newObj->class = fragCls; + newObj->lower = lower; + newObj->upper = upper; + newObj->value = value; + + return newObj; +} + + +// Deallocate fragment object +// - deallocate the frag object +void deallocate_Frag(void *item) { + if (item == NULL) return; + + // ensure that the allocation structures exist ... + ensureMemMgmt(); + + // Cast to appropriate object + Frag_t *fragObj = (Frag_t *)item; + + // nullify object + NULLIFY_OBJ(fragObj, Frag_t); + + // recycle the current fragment object + deallocateObject_MM(fragObj_MemMgr, sizeof(Frag_t), fragObj); +} + + +// Deallocate fragment object +// - deallocate the frag object (incl. the value) +void deallocateAll_Frag(void *item) { + if (item == NULL) return; + + // ensure that the allocation structures exist ... + ensureMemMgmt(); + + // Cast to appropriate object + Frag_t *fragObj = (Frag_t *)item; + + VoidFn_t finalFn = fragObj->class->finalObjFn; + + // Call the finalisation/deallocation function for the object value. + finalFn((void *)fragObj->value); + + // nullify object + NULLIFY_OBJ(fragObj, Frag_t); + + // recycle the current fragment object + deallocateObject_MM(fragObj_MemMgr, sizeof(Frag_t), fragObj); +} + + +// Fragment comparisons +FragCompare_t compare_Frag(Frag_t *thisFrag, Frag_t *otherFrag) { + // check for nulls + if (thisFrag == NULL) return FRAGMENT_UNDEF; + if (otherFrag == NULL) return FRAGMENT_UNDEF; + + // check consistency of fragment class + if (thisFrag->class != otherFrag->class) return FRAGMENT_UNDEF; + + CompareFn_t posnCompFn = thisFrag->class->posnCompFn; + + // Assume that: thisLower <= thisUpper + Posn_t thisLower = thisFrag->lower; + Posn_t thisUpper = thisFrag->upper; + + // Assume that: otherLower <= otherUpper + Posn_t otherLower = otherFrag->lower; + Posn_t otherUpper = otherFrag->upper; + + return fragmentCompare(posnCompFn, thisLower, thisUpper, otherLower, otherUpper); +} + + +FragCompare_t compareEnds_Frag(FragCls_t *fragCls, Posn_t thisLower, Posn_t thisUpper, Posn_t otherLower, Posn_t otherUpper) { + req_NonNull(fragCls); + + req_NonZero(thisLower); + req_NonZero(thisUpper); + req_NonZero(otherLower); + req_NonZero(otherUpper); + + CompareFn_t posnCompFn = fragCls->posnCompFn; + + return fragmentCompare(posnCompFn, thisLower, thisUpper, otherLower, otherUpper); +} + + +/******************************************************************************* + Show fragment +*******************************************************************************/ +static char showFragmentBuf[LINE_BUFSIZE+1]; + +// Showing fragments +char *show_Frag(void *item) { + if (item == NULL) return NULL_STR; + + Frag_t *curFrag = (Frag_t *)item; + + sprintf(showFragmentBuf, "0x%lu = (lower: %i, upper: %i, value: 0x%lu)" + , (Ptr_t)curFrag + , (int)curFrag->lower + , (int)curFrag->upper + , (Object_t)curFrag->value + ); + + return showFragmentBuf; +} + + +/******************************************************************************* + Static Method prototypes +*******************************************************************************/ +// ensure the allocation of memory management resources +static void ensureMemMgmt() { + if (fragCls_MemMgr == NULL) { + fragCls_MemMgr = new_MM(sizeof(FragCls_t)); + fragObj_MemMgr = new_MM(sizeof(Frag_t)); + } +} + +// fragment comparison code ... +static FragCompare_t fragmentCompare(CompareFn_t posnCompFn, + Posn_t thisLower, + Posn_t thisUpper, + Posn_t otherLower, + Posn_t otherUpper) { + if (posnCompFn(thisLower, otherLower) <= 0) { + // thisLower <= otherLower + + if (posnCompFn(otherUpper, thisUpper) <= 0) { + // thisLower <= otherLower <= otherUpper <= thisUpper + return FRAGMENT_CONTAINS; + } + else { + // thisUpper < otherUpper + + if (posnCompFn(thisUpper, otherLower) < 0) { + // thisLower <= thisUpper < otherLower <= otherUpper + return FRAGMENT_DISJOINT; + } + else { + // thisLower <= otherLower <= thisUpper < otherUpper + return FRAGMENT_OVERLAPS; + } + } + } + else { + + // otherLower < thisLower + if (posnCompFn(thisUpper, otherUpper) <= 0) { + // otherLower < thisLower <= thisUpper <= otherUpper + return FRAGMENT_CONTAINED; + } + else { + // otherUpper < thisUpper + + if (posnCompFn(otherUpper, thisLower) < 0) { + // otherLower <= otherUpper < thisLower <= thisUpper + return FRAGMENT_DISJOINT; + } + else { + // otherLower < thisLower <= otherUpper < thisUpper + return FRAGMENT_OVERLAPS; + } + } + } +} diff --git a/hash_fusion/lib/fragment.h b/hash_fusion/lib/fragment.h new file mode 100644 index 0000000000..538c3faf5c --- /dev/null +++ b/hash_fusion/lib/fragment.h @@ -0,0 +1,142 @@ +#ifndef __FRAGMENT_H__ +#define __FRAGMENT_H__ + +/******************************************************************************* + fragment.h + + Fragment classes and objects + + Author: brian.monahan@hpe.com + + (c) Copyright 2017 Hewlett Packard Enterprise Development LP + + 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. + + 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. +*******************************************************************************/ + +#include "utils.h" + + +/******************************************************************************* + Classes and Types +*******************************************************************************/ + +// Fragment Objects +typedef struct fragmentObj Frag_t; + +// Fragment System Class +// - specifies comparisons +typedef struct fragmentClass FragCls_t; + +// Type of value combiners +typedef Object_t (*CombineFn_t) (Object_t objA, Object_t objB); + +// Type of adjacency comparison outcomes (AdjData_t) +// - let acf(pa, pb) = ov, where acf is an adjacency comparison function. +// Then: ov is one of these outcome values, as specified below: +typedef enum { + ADJACENCY_UNDEF, // outcome not defined + LESS_THAN_NOT_ADJACENT, // pa < pb and pa is not adjacent to pb + LESS_THAN_ADJACENT, // pa < pb and pa is adjacent to pb + ADJACENCY_EQUAL, // pa == pb + GREATER_THAN_ADJACENT, // pa > pb and pa is adjacent to pb + GREATER_THAN_NOT_ADJACENT // pa > pb and pa is not adjacent to pb + } + AdjData_t; + +// Type of adjacency comparison functions +typedef AdjData_t (*AdjCompareFn_t) (Posn_t pa, Posn_t pb); + +// Fragment comparisons ... (subsumption of fragments) +typedef enum { + FRAGMENT_UNDEF, // Undefined/unspecified outcome + FRAGMENT_CONTAINED, // specified fragment is contained in other fragment + FRAGMENT_CONTAINS, // specified fragment contains other fragment + FRAGMENT_OVERLAPS, // specified fragment overlaps with other fragment + FRAGMENT_DISJOINT // specified fragment is disjoint from other fragment + } + FragCompare_t; + + +/******************************************************************************* + Structural definitions for fragmentClass and fragmentObj + - transparent definitions + - allows open access and update for these shared objects +*******************************************************************************/ +struct fragmentClass { + CompareFn_t posnCompFn; // position comparison function + AdjCompareFn_t adjCompFn; // adjacency comparison functio + CombineFn_t objCombFn; // object combination function + VoidFn_t finalObjFn; // finalise object function +}; + +struct fragmentObj { + FragCls_t *class; + Posn_t lower; + Posn_t upper; + Object_t value; +}; + + +/******************************************************************************* + Fragment Class Methods +*******************************************************************************/ +// +// Create a new fragment class (FragCls_t) +// - This provides a coordinated set of related methods: +// +// - Parametric methods: +// posnCompFn : position comparison function +// adjCompFn : adjacency comparison function +// objCombFn : object combination function +// finalObjFn : finalise object function +FragCls_t *new_FC(CompareFn_t posnCompFn, AdjCompareFn_t adjCompFn, CombineFn_t objCombFn, VoidFn_t finalObjFn); + + +// Deallocate fragment class +void deallocate_FC(void *item); + + +// Clones object +FragCls_t *clone_FC(FragCls_t *fragCls); + + +/******************************************************************************* + Fragment Object Methods +*******************************************************************************/ +// Create new fragment object (Frag_t) +// - Note: explicit fragment class pointer links to data specific operations. +Frag_t *new_Frag(FragCls_t *fragCls, Posn_t lower, Posn_t upper, Object_t value); + +// Deallocate fragment object +void deallocate_Frag(void *item); // deallocate the frag object itself +void deallocateAll_Frag(void *item); // deallocate the frag object (incl. the value) + +// Fragment comparisons ... +FragCompare_t compare_Frag(Frag_t *thisFrag, Frag_t *otherFrag); +FragCompare_t compareEnds_Frag(FragCls_t *fragCls, Posn_t thisLower, Posn_t thisUpper, Posn_t otherLower, Posn_t otherUpper); + +// Showing fragments +char *show_Frag(void *item); + +#endif diff --git a/hash_fusion/lib/fragmentMap.c b/hash_fusion/lib/fragmentMap.c new file mode 100644 index 0000000000..143f15a900 --- /dev/null +++ b/hash_fusion/lib/fragmentMap.c @@ -0,0 +1,1218 @@ +/******************************************************************************* + fragmentMap.c + + Provides fragment maps e.g. a map from a set of closed fragments to a space of + values. In essence, we have each map M with functional typing: SetOf(Fragments)->Value + so that: + + M = { intv |-> v | intv in S } + + The domain of the map is a set of closed fragments, based upon some finite + discrete linearly ordered set of points (e.g. subset of the integers, finite + subset of strings). + + A closed fragment of points is characterised by a pair [lower, upper] which + characterises the range defined by: { x | lower <= x <= upper } + + Note that when upper = lower, then [lower, upper] is the singleton set {x} + where x = lower = upper. + + We want to also merge adjacent fragments and therefore combine map values + for _adjacent_ fragments. If VCF is the value combiner operation, then: + + { ... [a, b] |-> v1, [b', c] |=> v2 ... } (where b and b' are adjacent) + + Becomes: + + { ... [a,c] |-> (v1 VCF v2) ... } + + (PS: This is an example of "multiset rewriting reduction") + + Two fragments are _adjacent_ iff: + + A.upper + 1 = B.lower OR B.upper + 1 = A.lower + + We can always merge two adjacent fragments to make a larger fragment. + + [3, 7] \/ [8, 10] = + [3, 5] \/ [6, 10] = [3, 10] + + An fragment map M is said to be _reduced_ when the domain of M is a set of + disjoint, non-adjacent closed fragments. + + Author: brian.monahan@hpe.com + + (c) Copyright 2017 Hewlett Packard Enterprise Development LP + + 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. + + 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. +*******************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "utils.h" +#include "alloc.h" +#include "rbTree.h" +#include "linkedList.h" +#include "fragment.h" +#include "fragmentMap.h" + +/******************************************************************************* + Classes and Types +*******************************************************************************/ + +// Fragment Maps - FragMap_t +struct fragmentMap { + FragCls_t *class; // Class info. determining comparison structures etc. + + FragMapKind_t fragKind; // This value determines the structural type of the data + Object_t data; // Opaque data structure pointer ... + + Posn_t current; + Boolean_t locked; +}; + + +/******************************************************************************* + Memory Management + - Opaque data objects have specific memory allocation defined elsewhere. +*******************************************************************************/ +static MemMgr_t *fragMap_MemMgr = NULL; + + +/******************************************************************************* + Static Method prototypes +*******************************************************************************/ +// Memory management helper +static void ensureMemMgmt(); + +// Allocate data object +static Object_t allocateDataObject(FragCls_t *fragCls, FragMapKind_t fragKind); + +// Deallocate data object +static void deallocateDataObject(FragMapKind_t fragKind, Object_t data); + +// Code to compare existing fragments in the fragment map with the proposed fragment +// - several outcomes possible +static FragCompare_t checkDisjointFragment(FragMap_t *fragMap, Posn_t lower, Posn_t upper); + +// Remove all fragments from the data contained in the proposed fragments +static void clearCoveredFragments(FragMap_t *fragMap, Posn_t lower, Posn_t upper); + +// Generic data object methods +static int getSize_MapObj(FragMap_t *fragMap); + +static Frag_t *getFirstFragment_MapObj(FragMap_t *fragMap); + +static Posn_t minPosn_MapObj(FragMap_t *fragMap); +static Posn_t maxPosn_MapObj(FragMap_t *fragMap); + +static Posn_t nextPosn_MapObj(FragMap_t *fragMap, Posn_t point, Boolean_t allowEQ); +static Posn_t priorPosn_MapObj(FragMap_t *fragMap, Posn_t point, Boolean_t allowEQ); + +static Frag_t *lookup_MapObj(FragMap_t *fragMap, Posn_t point); +static Frag_t *delete_MapObj(FragMap_t *fragMap, Posn_t point); +static Frag_t *insert_MapObj(FragMap_t *fragMap, Posn_t point, Frag_t *newFrag); + +// Single Fragment methods +static Boolean_t addPoint_SingleFrag(FragMap_t *fragMap, Posn_t point, Object_t value); +static Boolean_t addFragment_SingleFrag(FragMap_t *fragMap, Posn_t lower, Posn_t upper, Object_t value); + +static Posn_t minPosn_SingleFrag(Frag_t *frag); +static Posn_t maxPosn_SingleFrag(Frag_t *frag); + +static Posn_t nextPosn_SingleFrag(CompareFn_t posnCompFn, Frag_t *frag, Posn_t point, Boolean_t allowEQ); +static Posn_t priorPosn_SingleFrag(CompareFn_t posnCompFn, Frag_t *frag, Posn_t point, Boolean_t allowEQ); + +static Frag_t *lookup_SingleFrag(CompareFn_t posnCompFn, Frag_t *frag, Posn_t point); + + +// Ordered List object methods +static Posn_t minPosn_OrdList(LinkList_t *fragSeq); +static Posn_t maxPosn_OrdList(LinkList_t *fragSeq); + +static Posn_t nextPosn_OrdList(CompareFn_t posnCompFn, LinkList_t *fragSeq, Posn_t point, Boolean_t allowEQ); +static Posn_t priorPosn_OrdList(CompareFn_t posnCompFn, LinkList_t *fragSeq, Posn_t point, Boolean_t allowEQ); + +static Frag_t *lookup_OrdList(CompareFn_t posnCompFn, LinkList_t *fragSeq, Posn_t point); + +static Frag_t *delete_OrdList(FragCls_t *fragCls, LinkList_t *fragSeq, Posn_t point); + +static Frag_t *insert_OrdList(FragCls_t *fragCls, LinkList_t *fragSeq, Posn_t point, Frag_t *newFrag); + + +/******************************************************************************* + Fragment Map Methods +*******************************************************************************/ +// Create a new fragment map (FragMap_t) +// - Assume that the FragCls_t object is never shared (i.e. always fresh and can be dealocated). +FragMap_t *new_FM(FragCls_t *fragCls, FragMapKind_t fragKind) { + req_NonNull(fragCls); + + // ensure that the allocation structures exist ... + ensureMemMgmt(); + + // allocate new Tree + FragMap_t *newMap = allocateObject_MM(fragMap_MemMgr); + + // set attributes + newMap->class = fragCls; + newMap->fragKind = fragKind; + newMap->data = allocateDataObject(fragCls, fragKind); + + newMap->current = NULL_POSN; + newMap->locked = FALSE; + + return newMap; +} + + +// Deallocate fragment map +void deallocate_FM(void *item) { + if (item == NULL) return; + + FragMap_t *fragMap = (FragMap_t *)item; + + // Deallocate the frag class + // - This assumes that the object is never shared ... + deallocate_FC(fragMap->class); + + // Deallocate the data object ... + deallocateDataObject(fragMap->fragKind, fragMap->data); + + // Nullify map object + NULLIFY_OBJ(fragMap, FragMap_t); + + // recycle the current map object + deallocateObject_MM(fragMap_MemMgr, sizeof(FragMap_t), fragMap); +} + + +// Add a point mapping to given fragment map +// - Adds the point to the mapping and then reduces the domain set +// by combining with adjacent fragments in the mapping. +// - Returns TRUE if addition was successful, FALSE otherwise. +Boolean_t addPoint_FM(FragMap_t *fragMap, Posn_t point, Object_t value) { + req_NonNull(fragMap); + + // Check if map is locked + if (fragMap->locked) return FALSE; + + // Check if point is already within the data + if (lookupFragment_FM(fragMap, point) != NULL) return FALSE; + + // Handle fragment kind == NULL_FRAG_MAP + if (fragMap->fragKind == NULL_FRAG_MAP) { + return addPoint_SingleFrag(fragMap, point, value); + } + + FragCls_t *sysClass = fragMap->class; + AdjCompareFn_t adjCompFn = sysClass->adjCompFn; + CombineFn_t objCombFn = sysClass->objCombFn; + + // Records current fragment containing the new point ... + // - This will be inserted at the end. + Frag_t *curFragment = NULL; + + // Current point at which curFragment is inserted into mapping + // - This is always equal to: curFragment->lower + Posn_t bindPoint = NULL_POSN; + + // Get next point + // - this works even though point is _NOT_ already in the data ... + Posn_t nextLowerPoint = nextPosn_MapObj(fragMap, point, FALSE); + + if (adjCompFn(point, nextLowerPoint) == LESS_THAN_ADJACENT) { + // Combine the next item ... + Frag_t *nextFrag = lookup_MapObj(fragMap, nextLowerPoint); + Object_t nextValue = nextFrag->value; + + // Unbind the entry for nextFrag in fragMap + delete_MapObj(fragMap, nextLowerPoint); + + // Calculate new value + Object_t newValue = objCombFn(value, nextValue); + + // Update the nextFrag object + nextFrag->lower = point; + nextFrag->value = newValue; + + // Assign the current fragment to be nextFrag (!= NULL) + curFragment = nextFrag; + bindPoint = point; + } + + Posn_t priorLowerPoint = priorPosn_MapObj(fragMap, point, FALSE); + + Frag_t *priorFrag = lookup_MapObj(fragMap, priorLowerPoint); + + Posn_t priorUpperPoint = (priorFrag == NULL ? NULL_POSN : priorFrag->upper); + + if (adjCompFn(priorUpperPoint, point) == LESS_THAN_ADJACENT) { + Object_t priorValue = priorFrag->value; + Object_t nextValue = value; + Posn_t newUpperPoint = point; + + // combine with curFragment if not specified + if (curFragment != NULL) { + newUpperPoint = curFragment->upper; + nextValue = curFragment->value; + + // Preserve value ... + curFragment->value = ZERO_VAL; + + // Deallocate current fragment + deallocate_Frag(curFragment); + } + + // Unbind the entry for priorFrag in fragMap + delete_MapObj(fragMap, priorLowerPoint); + + // Get new value for extended fragment + Object_t newValue = objCombFn(priorValue, nextValue); + + // Update the prior fragment object + priorFrag->upper = newUpperPoint; + priorFrag->value = newValue; + + // Set the current fragment containing the point ... + curFragment = priorFrag; + bindPoint = priorLowerPoint; + } + + if (curFragment == NULL) { + // insert point as a singleton ... + curFragment = new_Frag(sysClass, point, point, value); + bindPoint = point; + } + insert_MapObj(fragMap, bindPoint, curFragment); + + return TRUE; +} + + +// Add a consistent fragment to given fragment map +// - Adds the fragment to the mapping and then reduces the domain set +// by combining with adjacent fragments in the mapping. +// - Returns TRUE if addition was successful, FALSE otherwise. +Boolean_t addFragment_FM(FragMap_t *fragMap, Posn_t lower, Posn_t upper, Object_t value) { + req_NonNull(fragMap); + + // Check if map is locked + if (fragMap->locked) return FALSE; + + FragCls_t *fragCls = fragMap->class; + + // Check if endpoints are already within the data + switch (checkDisjointFragment(fragMap, lower, upper)) { + // Add the new fragment + case FRAGMENT_DISJOINT: + break; + + // Nothing to do. The proposed fragment already exists or is contained + // by some other fragment. + case FRAGMENT_CONTAINED: + return TRUE; + + // Clear out fragments covered by proposed fragment + // and then add the new fragment + case FRAGMENT_CONTAINS: + clearCoveredFragments(fragMap, lower, upper); + break; + + // Failure detected. + default: + return FALSE; + } + + // Handle fragment kind == NULL_FRAG_MAP + if (fragMap->fragKind == NULL_FRAG_MAP) { + return addFragment_SingleFrag(fragMap, lower, upper, value); + } + + FragCls_t *sysClass = fragMap->class; + AdjCompareFn_t adjCompFn = sysClass->adjCompFn; + CombineFn_t objCombFn = sysClass->objCombFn; + + // Records current fragment containing the proposed fragment ... + Frag_t *curFragment = NULL; + + // Current point at which curFragment is inserted into mapping + // - This is always equal to: curFragment->lower + Posn_t bindPoint = NULL_POSN; + + // Get next point + // - this works even though upper is _NOT_ already in the data ... + Posn_t nextLowerPoint = nextPosn_MapObj(fragMap, upper, FALSE); + + if (adjCompFn(upper, nextLowerPoint) == LESS_THAN_ADJACENT) { + // Combine the next item ... + Frag_t *nextFrag = lookup_MapObj(fragMap, nextLowerPoint); + Object_t nextValue = nextFrag->value; + + // Unbind the entry for nextFrag in fragMap + delete_MapObj(fragMap, nextLowerPoint); + + Object_t newValue = objCombFn(value, nextValue); + + // Update the nextFrag object + nextFrag->lower = lower; + nextFrag->value = newValue; + + // Assign the current fragment to be nextFrag (!= NULL) + curFragment = nextFrag; + bindPoint = lower; + } + + // Get prior upper point + Posn_t priorLowerPoint = priorPosn_MapObj(fragMap, lower, FALSE); + Frag_t *priorFrag = lookup_MapObj(fragMap, priorLowerPoint); + Posn_t priorUpperPoint = (priorFrag == NULL ? NULL_POSN : priorFrag->upper); + + if (adjCompFn(priorUpperPoint, lower) == LESS_THAN_ADJACENT) { + Object_t priorValue = priorFrag->value; + Object_t nextValue = value; + Posn_t newUpperPoint = upper; + + // combine with curFragment if not specified + if (curFragment != NULL) { + newUpperPoint = curFragment->upper; + nextValue = curFragment->value; + + // Preserve value ... + curFragment->value = ZERO_VAL; + + // Deallocate the fragment + deallocate_Frag(curFragment); + } + + // Unbind the entry for priorFrag in fragMap + delete_MapObj(fragMap, priorLowerPoint); + + // Get new value for extended fragment + Object_t newValue = objCombFn(priorValue, nextValue); + + // Update the prior fragment object + priorFrag->upper = newUpperPoint; + priorFrag->value = newValue; + + // Set the current fragment containing the point ... + curFragment = priorFrag; + bindPoint = priorLowerPoint; + } + + if (curFragment == NULL) { + // insert point as a singleton ... + curFragment = new_Frag(sysClass, lower, upper, value); + bindPoint = lower; + } + insert_MapObj(fragMap, bindPoint, curFragment); + + return TRUE; +} + + +// Lookup covering fragment for a given point. +// - This determines the fragment that covers the given point, and returns it. +// - Returns NULL if not found +Frag_t *lookupFragment_FM(FragMap_t *fragMap, Posn_t point) { + req_NonNull(fragMap); + + if (point == NULL_POSN) return NULL; + + CompareFn_t posnCompFn = fragMap->class->posnCompFn; + + // look for any prior point (including equality). + Posn_t priorLowerPoint = priorPosn_MapObj(fragMap, point, TRUE); + + // check priorLowerPoint for NULL_POSN + if (priorLowerPoint == NULL_POSN) return NULL; + + + Frag_t *priorFrag = lookup_MapObj(fragMap, priorLowerPoint); + req_NonNull(priorFrag); // priorFrag should be non-NULL + + Posn_t priorUpperPoint = priorFrag->upper; + req_NonZero(priorUpperPoint); // priorUpperPoint should be non-zero + + // check if priorFrag **doesn't** cover the point ... + if (posnCompFn(point, priorUpperPoint) > 0) return NULL; + return priorFrag; +} + + +// Size of fragment map - i.e. number of disjoint fragments +int getSize_FM(FragMap_t *fragMap) { + req_NonNull(fragMap); + + return getSize_MapObj(fragMap); +} + + +// Get the first fragment +// - Returns NULL if empty +Frag_t *getFirstFragment_FM(FragMap_t *fragMap){ + req_NonNull(fragMap); + + return getFirstFragment_MapObj(fragMap); +} + + +// Enumerate fragment point mappings +// - Checks if map is locked (i.e. being enumerated). +// - Enumerates fragment objects in order. +// - Returns NULL, when completed. +// - Changes are locked out during enumeration. +Boolean_t isLocked_FM(FragMap_t *fragMap) { + req_NonNull(fragMap); + + if (fragMap->current == NULL_POSN) { + fragMap->locked = FALSE; + } + + return fragMap->locked; +} + +Frag_t *start_EnumMap_FM(FragMap_t *fragMap) { + req_NonNull(fragMap); + if (fragMap->locked) return NULL; + + Posn_t initPosn = minPosn_MapObj(fragMap); + + // checks position is valid ... + if (initPosn == NULL_POSN) { + fragMap->locked = FALSE; + return NULL; + } + + fragMap->current = initPosn; + fragMap->locked = TRUE; + + // return value + return (Frag_t *)lookup_MapObj(fragMap, initPosn); +} + +Frag_t *next_EnumMap_FM(FragMap_t *fragMap) { + req_NonNull(fragMap); + + if (!fragMap->locked) return NULL; + + if (fragMap->current == NULL_POSN) { + fragMap->locked = FALSE; + return NULL; + } + + // set current position + Posn_t curPosn = nextPosn_MapObj(fragMap, fragMap->current, FALSE); + Frag_t *curVal = (Frag_t *)lookup_MapObj(fragMap, curPosn); + fragMap->current = curPosn; + + if (curPosn == NULL_POSN || curVal == NULL) { + fragMap->locked = FALSE; + return NULL; + } + + // return value + return curVal; +} + +void stop_EnumMap_FM(FragMap_t *fragMap) { + req_NonNull(fragMap); + + fragMap->current = NULL_POSN; + fragMap->locked = FALSE; +} + + +/******************************************************************************* + Static methods +*******************************************************************************/ +// ensure the allocation of memory management resources +static void ensureMemMgmt() { + if (fragMap_MemMgr == NULL) { + fragMap_MemMgr = new_MM(sizeof(FragMap_t)); + } +} + + +// Allocate data object +// - no object deallocation functions are set ... +static Object_t allocateDataObject(FragCls_t *fragCls, FragMapKind_t fragKind) { + RBTree_t *newTree = NULL; + + switch (fragKind) { + case NULL_FRAG_MAP: + return (Object_t)NULL; // Actual object allocated when fragment added. + + case LINEAR_LIST_FRAG_MAP: + return (Object_t)new_LL(); + + case BINARY_TREE_FRAG_MAP: + newTree = new_RBT(fragCls->posnCompFn); + setAllowUpdates_RBT(newTree, TRUE); + setAllowNullKey_RBT(newTree, FALSE); + return (Object_t)newTree; + + default: + diagnostic("allocateDataObject: Bad value for fragment kind %i", fragKind); + error_exit(); + } +} + +// Deallocate data object +// - the associated fragments should here be deallocated. +static void deallocateDataObject(FragMapKind_t fragKind, Object_t data) { + switch(fragKind) { + case NULL_FRAG_MAP: + deallocate_Frag((Frag_t *)data); + return; + + case LINEAR_LIST_FRAG_MAP: + deallocateWithFinaliser_LL((LinkList_t *)data, deallocate_Frag); + return; + + case BINARY_TREE_FRAG_MAP: + deallocateWithFinaliser_RBT((RBTree_t *)data, deallocate_Frag); + return; + + default: + diagnostic("deallocateDataObject: Bad value for fragment kind %i", fragKind); + error_exit(); + } +} + + +// Code to compare existing fragments in the fragment map with the proposed fragment +// - several outcomes possible +static FragCompare_t checkDisjointFragment(FragMap_t *fragMap, Posn_t lower, Posn_t upper) { + req_NonNull(fragMap); + req_NonNull(fragMap->class); + + if (lower == NULL_POSN) return FRAGMENT_UNDEF; + if (upper == NULL_POSN) return FRAGMENT_UNDEF; + + CompareFn_t posnCompFn = fragMap->class->posnCompFn; + + // check for the proposed fragment, lower <= upper + if (posnCompFn(upper, lower) < 0) return FRAGMENT_UNDEF; + + // Find fragments in data covering each endpoint + Frag_t *startFrag = lookupFragment_FM(fragMap, lower); + Frag_t *endFrag = lookupFragment_FM(fragMap, upper); + + // Check if endpoints miss the fragments + if (startFrag == NULL && endFrag == NULL) { + // Neither startFrag or endFrag fragment is defined + // However, the proposed fragment could contain fragments from the data. + + Posn_t nextPoint = nextPosn_MapObj(fragMap, lower, FALSE); + + if (nextPoint == NULL_POSN || posnCompFn(upper, nextPoint) < 0) { + // Either nextPoint does not exist OR upper < nextPoint + // This means the proposed fragment is disjoint with fragments in the map. + return FRAGMENT_DISJOINT; + } + + // lower < nextPoint < upper + return FRAGMENT_CONTAINS; + } + + // At least one of startFrag or endFrag is non-NULL ... + if (startFrag != endFrag) { + // This means that the two fragments are distinct and cannot both be NULL. + // Therefore, at least one fragment contains one of lower or upper. + // This means either startFrag or endFrag overlaps with the proposed fragment. + return FRAGMENT_OVERLAPS; + } + + // Now have that startFrag == endFrag + Posn_t upperStartFrag = startFrag->upper; + + if (posnCompFn(upper, upperStartFrag) <= 0) { + return FRAGMENT_CONTAINED; + } + + return FRAGMENT_UNDEF; +} + + +// Remove all fragments from the data contained in the proposed fragments +static void clearCoveredFragments(FragMap_t *fragMap, Posn_t lower, Posn_t upper) { + req_NonNull(fragMap); + req_NonNull(fragMap->class); + + if (lower == NULL_POSN || upper == NULL_POSN) return; + + CompareFn_t posnCompFn = fragMap->class->posnCompFn; + + Posn_t curPosn = nextPosn_MapObj(fragMap, lower, FALSE); + + while (curPosn != NULL_POSN && posnCompFn(curPosn, upper) <= 0) { + delete_MapObj(fragMap, curPosn); + curPosn = nextPosn_MapObj(fragMap, curPosn, FALSE); + } +} + + +/******************************************************************************* + Generic data object methods +*******************************************************************************/ +static Frag_t *insert_MapObj(FragMap_t *fragMap, Posn_t point, Frag_t *newFrag) { + req_NonNull(fragMap); + req_NonNull(fragMap->class); + + switch(fragMap->fragKind) { + case LINEAR_LIST_FRAG_MAP: + return insert_OrdList(fragMap->class, (LinkList_t *)fragMap->data, point, newFrag); + + case BINARY_TREE_FRAG_MAP: + return insert_RBT((RBTree_t *)fragMap->data, (Key_t)point, newFrag); + + default: + diagnostic("insert_MapObj: Bad value for fragment kind %i", fragMap->fragKind); + error_exit(); + } +} + +static Frag_t *delete_MapObj(FragMap_t *fragMap, Posn_t point) { + req_NonNull(fragMap); + + switch(fragMap->fragKind) { + case LINEAR_LIST_FRAG_MAP: + return delete_OrdList(fragMap->class, (LinkList_t *)fragMap->data, point); + + case BINARY_TREE_FRAG_MAP: + return delete_RBT((RBTree_t *)fragMap->data, (Key_t)point); + + default: + diagnostic("delete_MapObj: Bad value for fragment kind %i", fragMap->fragKind); + error_exit(); + } +} + +static int getSize_MapObj(FragMap_t *fragMap) { + req_NonNull(fragMap); + + switch(fragMap->fragKind) { + case NULL_FRAG_MAP: + return ((Frag_t *)fragMap->data == NULL ? 0 : 1); + + case LINEAR_LIST_FRAG_MAP: + return getLength_LL((LinkList_t *)fragMap->data); + + case BINARY_TREE_FRAG_MAP: + return getSize_RBT((RBTree_t *)fragMap->data); + + default: + diagnostic("getSize_MapObj: Bad value for fragment kind %i", fragMap->fragKind); + error_exit(); + } +} + +static Frag_t *getFirstFragment_MapObj(FragMap_t *fragMap) { + req_NonNull(fragMap); + + switch(fragMap->fragKind) { + case NULL_FRAG_MAP: + return (Frag_t *)fragMap->data; + + case LINEAR_LIST_FRAG_MAP: + return getTopObject_LL((LinkList_t *)fragMap->data); + + case BINARY_TREE_FRAG_MAP: + return getFirstElement_RBT((RBTree_t *)fragMap->data); + + default: + diagnostic("getSize_MapObj: Bad value for fragment kind %i", fragMap->fragKind); + error_exit(); + } +} + +static Posn_t minPosn_MapObj(FragMap_t *fragMap) { + req_NonNull(fragMap); + + switch(fragMap->fragKind) { + case NULL_FRAG_MAP: + return minPosn_SingleFrag((Frag_t *)fragMap->data); + + case LINEAR_LIST_FRAG_MAP: + return minPosn_OrdList((LinkList_t *)fragMap->data); + + case BINARY_TREE_FRAG_MAP: + return (Posn_t)minKey_RBT((RBTree_t *)fragMap->data); + + default: + diagnostic("minPosn_MapObj: Bad value for fragment kind %i", fragMap->fragKind); + error_exit(); + } +} + +static Posn_t maxPosn_MapObj(FragMap_t *fragMap) { + req_NonNull(fragMap); + + switch(fragMap->fragKind) { + case NULL_FRAG_MAP: + return maxPosn_SingleFrag((Frag_t *)fragMap->data); + + case LINEAR_LIST_FRAG_MAP: + return maxPosn_OrdList((LinkList_t *)fragMap->data); + + case BINARY_TREE_FRAG_MAP: + return (Posn_t)maxKey_RBT((RBTree_t *)fragMap->data); + + default: + diagnostic("maxPosn_MapObj: Bad value for fragment kind %i", fragMap->fragKind); + error_exit(); + } +} + + +static Posn_t nextPosn_MapObj(FragMap_t *fragMap, Posn_t point, Boolean_t allowEQ) { + req_NonNull(fragMap); + req_NonNull(fragMap->class); + + switch(fragMap->fragKind) { + case NULL_FRAG_MAP: + return nextPosn_SingleFrag(fragMap->class->posnCompFn, (Frag_t *)fragMap->data, point, allowEQ); + + case LINEAR_LIST_FRAG_MAP: + return nextPosn_OrdList(fragMap->class->posnCompFn, (LinkList_t *)fragMap->data, point, allowEQ); + + case BINARY_TREE_FRAG_MAP: + return (Posn_t)nextKey_RBT((RBTree_t *)fragMap->data, (Key_t)point, allowEQ); + + default: + diagnostic("nextPosn_MapObj: Bad value for fragment kind %i", fragMap->fragKind); + error_exit(); + } +} + +static Posn_t priorPosn_MapObj(FragMap_t *fragMap, Posn_t point, Boolean_t allowEQ) { + req_NonNull(fragMap); + + switch(fragMap->fragKind) { + case NULL_FRAG_MAP: + return priorPosn_SingleFrag(fragMap->class->posnCompFn, (Frag_t *)fragMap->data, point, allowEQ); + + case LINEAR_LIST_FRAG_MAP: + return priorPosn_OrdList(fragMap->class->posnCompFn, (LinkList_t *)fragMap->data, point, allowEQ); + + case BINARY_TREE_FRAG_MAP: + return (Posn_t)priorKey_RBT((RBTree_t *)fragMap->data, (Key_t)point, allowEQ); + + default: + diagnostic("priorPosn_MapObj: Bad value for fragment kind %i", fragMap->fragKind); + error_exit(); + } +} + +static Frag_t *lookup_MapObj(FragMap_t *fragMap, Posn_t point) { + req_NonNull(fragMap); + + if (point == NULL_POSN) return NULL; + + switch(fragMap->fragKind) { + case NULL_FRAG_MAP: + return lookup_SingleFrag(fragMap->class->posnCompFn, (Frag_t *)fragMap->data, point); + + case LINEAR_LIST_FRAG_MAP: + return lookup_OrdList(fragMap->class->posnCompFn, (LinkList_t *)fragMap->data, point); + + case BINARY_TREE_FRAG_MAP: + return lookup_RBT((RBTree_t *)fragMap->data, (Key_t)point); + + default: + diagnostic("getAllowUpdates_MapObj: Bad value for fragment kind %i", fragMap->fragKind); + error_exit(); + } +} + + +/******************************************************************************* + Single Fragment Methods + - Fragment map consists of a single fragment ... +*******************************************************************************/ +static Boolean_t addPoint_SingleFrag(FragMap_t *fragMap, Posn_t point, Object_t value) { + req_NonNull(fragMap); + + FragCls_t *sysClass = fragMap->class; + AdjCompareFn_t adjCompFn = sysClass->adjCompFn; + CombineFn_t objCombFn = sysClass->objCombFn; + + // get current fragment + Frag_t *curFrag = (Frag_t *)fragMap->data; + + if (curFrag == NULL) { + // Create new fragment ... + curFrag = new_Frag(fragMap->class, point, point, value); + + // update data component ... + fragMap->data = (Object_t)curFrag; + + return TRUE; + } + else { + if (adjCompFn(curFrag->upper, point) == LESS_THAN_ADJACENT) { + // Updating curFrag with new combined value ... + curFrag->value = objCombFn(curFrag->value, value); + + // Updating upper range of curFrag + curFrag->upper = point; + + return TRUE; + } + else if (adjCompFn(point, curFrag->lower) == LESS_THAN_ADJACENT) { + // Updating curFrag with new combined value ... + curFrag->value = objCombFn(value, curFrag->value); + + // Updating lower range of curFrag + curFrag->lower = point; + + return TRUE; + } + else { + return FALSE; + } + } +} + + +static Boolean_t addFragment_SingleFrag(FragMap_t *fragMap, Posn_t lower, Posn_t upper, Object_t value) { + req_NonNull(fragMap); + + FragCls_t *sysClass = fragMap->class; + AdjCompareFn_t adjCompFn = sysClass->adjCompFn; + CombineFn_t objCombFn = sysClass->objCombFn; + + // get current fragment + Frag_t *curFrag = (Frag_t *)fragMap->data; + + if (curFrag == NULL) { + // Create new fragment ... + curFrag = new_Frag(fragMap->class, lower, upper, value); + + // update data component ... + fragMap->data = (Object_t)curFrag; + + return TRUE; + } + else { + if (adjCompFn(curFrag->upper, lower) == LESS_THAN_ADJACENT) { + // Updating curFrag with new combined value ... + curFrag->value = objCombFn(curFrag->value, value); + + // Updating upper range of curFrag + curFrag->upper = upper; + + return TRUE; + } + else if (adjCompFn(upper, curFrag->lower) == LESS_THAN_ADJACENT) { + // Updating curFrag with new combined value ... + curFrag->value = objCombFn(value, curFrag->value); + + // Updating lower range of curFrag + curFrag->lower = lower; + + return TRUE; + } + else { + return FALSE; + } + } +} + +static Posn_t minPosn_SingleFrag(Frag_t *frag) { + if (frag == NULL) return NULL_POSN; + + return frag->lower; +} + +static Posn_t maxPosn_SingleFrag(Frag_t *frag) { + if (frag == NULL) return NULL_POSN; + + return frag->upper; +} + +static Posn_t nextPosn_SingleFrag(CompareFn_t posnCompFn, Frag_t *frag, Posn_t point, Boolean_t allowEQ) { + req_NonNull(frag); + + Posn_t lower = frag->lower; + + int indication = posnCompFn(point, lower); + + if (indication < 0) return lower; + if (indication == 0 && allowEQ) return lower; + + return NULL_POSN; +} + +static Posn_t priorPosn_SingleFrag(CompareFn_t posnCompFn, Frag_t *frag, Posn_t point, Boolean_t allowEQ) { + req_NonNull(frag); + + Posn_t lower = frag->lower; + + int indication = posnCompFn(lower, point); + + if (indication < 0) return lower; + if (indication == 0 && allowEQ) return lower; + + return NULL_POSN; +} + +static Frag_t *lookup_SingleFrag(CompareFn_t posnCompFn, Frag_t *frag, Posn_t point) { + if (point == NULL_POSN) return NULL; + + return (posnCompFn(point, frag->lower) == 0 ? frag : NULL); +} + + +/******************************************************************************* + Ordered List Methods + - Fragment map is list-based +*******************************************************************************/ +static Frag_t *insert_OrdList(FragCls_t *fragCls, LinkList_t *fragSeq, Posn_t point, Frag_t *newFrag) { + req_NonNull(fragSeq); + + + CompareFn_t posnCompFn = fragCls->posnCompFn; + VoidFn_t finalObjFn = fragCls->finalObjFn; + + // No NULL_POSNs are allowed. + if (point == NULL_POSN) return NULL; + + ListNode_t *prevNode = NULL; + ListNode_t *curNode = getTopNode_LL(fragSeq); + + ListNode_t *newNode = NULL; // node to be added ... + ListNode_t *nextNode = NULL; // successor to new node + + Frag_t *curFrag = NULL; + Posn_t curPosn = NULL_POSN; + + int indication = 0; + while (curNode != NULL) { + curFrag = (Frag_t *)getNodeObject_LL(curNode); + curPosn = curFrag->lower; + + indication = posnCompFn(curPosn, point); + if (indication == 0) { + // Update the found node with new frag ... + setNodeObject_LL(curNode, newFrag); + + finalObjFn(curFrag); + return curFrag; + } + else if (indication > 0) { + // Make new node with new frag ... + newNode = newNodeObject_LL(newFrag, NULL); + + if (prevNode == NULL) { + // Insert as head of list + nextNode = getTopNode_LL(fragSeq); + setTopNode_LL(fragSeq, newNode); + } + else { + nextNode = curNode; + setNextNode_LL(prevNode, newNode); + } + + // Splice new node into list betwen prevNode and curNode + setNextNode_LL(newNode, nextNode); + + // update the list + incrLength_LL(fragSeq, 1); + if (nextNode == NULL) { + setEndNode_LL(fragSeq, newNode); + } + + return NULL; + } + + prevNode = curNode; + curNode = getNextNode_LL(curNode); + } + + // At end of list ... + newNode = newNodeObject_LL(newFrag, NULL); + + if (prevNode == NULL) { + // List is currently empty ... + setTopNode_LL(fragSeq, newNode); + } + else { + setNextNode_LL(prevNode, newNode); + } + + // update the list + incrLength_LL(fragSeq, 1); // length has increased by 1 + setEndNode_LL(fragSeq, newNode); // newNode is now the end node + + return NULL; +} + + +static Frag_t *delete_OrdList(FragCls_t *fragCls, LinkList_t *fragSeq, Posn_t point) { + req_NonNull(fragSeq); + + ListNode_t *newNode = NULL; + + CompareFn_t posnCompFn = fragCls->posnCompFn; + + // No NULL_POSNs are allowed. + if (point == NULL_POSN) return NULL; + + ListNode_t *prevNode = NULL; + ListNode_t *curNode = getTopNode_LL(fragSeq); + ListNode_t *nextNode = NULL; + + Frag_t *curFrag = NULL; + Posn_t curPosn = NULL_POSN; + + int indication = 0; + while (curNode != NULL) { + curFrag = (Frag_t *)getNodeObject_LL(curNode); + curPosn = curFrag->lower; + + nextNode = getNextNode_LL(curNode); + + indication = posnCompFn(curPosn, point); + if (indication == 0) { + // found node to delete + + if (prevNode == NULL) { + setTopNode_LL(fragSeq, nextNode); + } + else { + setNextNode_LL(prevNode, nextNode); + } + + // update the list ... + incrLength_LL(fragSeq, -1); + if (nextNode == NULL) { + setEndNode_LL(fragSeq, prevNode); + } + + // deallocate list node + deallocateNode_LL(curNode, nullVoidFn); + + // return current fragment + return curFrag; + + } + else if (indication > 0) { + // nothing to delete + return NULL; + } + + prevNode = curNode; + curNode = nextNode; + } + return NULL; +} + + +static Posn_t minPosn_OrdList(LinkList_t *fragSeq) { + if (getLength_LL(fragSeq) == 0) return NULL_POSN; + + Frag_t *frag = (Frag_t *)getTopObject_LL(fragSeq); + return frag->lower; +} + +static Posn_t maxPosn_OrdList(LinkList_t *fragSeq) { + if (getLength_LL(fragSeq) == 0) return NULL_POSN; + + Frag_t *frag = (Frag_t *)getEndObject_LL(fragSeq); + return frag->upper; +} + +static Posn_t nextPosn_OrdList(CompareFn_t posnCompFn, LinkList_t *fragSeq, Posn_t point, Boolean_t allowEQ) { + if (point == NULL_POSN) return NULL_POSN; + + ListNode_t *curNode = getTopNode_LL(fragSeq); + Frag_t *curFrag = NULL; + Posn_t curPosn = NULL_POSN; + + int indicator = 0; + + // walking the list + while (curNode != NULL) { + curFrag = (Frag_t *)getNodeObject_LL(curNode); + curPosn = curFrag->lower; + + indicator = posnCompFn(curPosn, point); + if (allowEQ && indicator == 0) return curPosn; + if (indicator > 0) return curPosn; + + curNode = getNextNode_LL(curNode); + } + return NULL_POSN; +} + +static Posn_t priorPosn_OrdList(CompareFn_t posnCompFn, LinkList_t *fragSeq, Posn_t point, Boolean_t allowEQ) { + + if (point == NULL_POSN) return NULL_POSN; + + ListNode_t *curNode = getTopNode_LL(fragSeq); + Frag_t *curFrag = NULL; + Posn_t curPosn = NULL_POSN; + Posn_t prevPosn = NULL_POSN; + + int indicator = 0; + + // walking the list + while (curNode != NULL) { + curFrag = (Frag_t *)getNodeObject_LL(curNode); + prevPosn = curPosn; + curPosn = curFrag->lower; + + indicator = posnCompFn(curPosn, point); + if (allowEQ && indicator == 0) return curPosn; + if (indicator >= 0) return prevPosn; + + curNode = getNextNode_LL(curNode); + } + return curPosn; +} + +static Frag_t *lookup_OrdList(CompareFn_t posnCompFn, LinkList_t *fragSeq, Posn_t point) { + if (point == NULL_POSN) return NULL; + + ListNode_t *curNode = getTopNode_LL(fragSeq); + Frag_t *curFrag; + Posn_t curPosn; + + // walking the list + while (curNode != NULL) { + curFrag = (Frag_t *)getNodeObject_LL(curNode); + curPosn = curFrag->lower; + + if (posnCompFn(curPosn, point) == 0) return curFrag; + + curNode = getNextNode_LL(curNode); + } + + return NULL; + +} diff --git a/hash_fusion/lib/fragmentMap.h b/hash_fusion/lib/fragmentMap.h new file mode 100644 index 0000000000..aa792e98f9 --- /dev/null +++ b/hash_fusion/lib/fragmentMap.h @@ -0,0 +1,148 @@ +#ifndef __FRAGMENT_MAP_H__ +#define __FRAGMENT_MAP_H__ + +/******************************************************************************* + fragmentMap.h + + Provides fragment maps e.g. a map from fragments to a space of values. + A fragment is a pair consisting of a fragment and its valuation. + + In essence, we have each map M with functional typing: Fragments -> Value + so that: + + M = { intv |-> v | intv in S } + + The domain of the map is a set of closed fragments, based upon some finite + discrete linearly ordered set of points (e.g. subset of the integers, finite + subset of strings). + + A closed fragment of points is characterised by a pair [lower, upper] which + is defined by: { x | lower <= x <= upper } + + Note that when upper = lower, then [lower, upper] is the singleton set {x} + where x = lower = upper. + + We want to also merge adjacent fragments and therefore combine map values + for _adjacent_ fragments. If VCF is the value combiner operation, then: + + { ... [a, b] |-> v1, [b', c] |=> v2 ... } (where b and b' are adjacent) + + Becomes: + + { ... [a,c] |-> (v1 VCF v2) ... } + + (An example of "multiset rewriting reduction") + + Two fragments are _adjacent_ iff: + + A.upper + 1 = B.lower OR B.upper + 1 = A.lower + + We can always merge two adjacent fragments to make a larger fragment. + + [3, 7] \/ [8, 10] = + [3, 5] \/ [6, 10] = [3, 10] + + An fragment map M is said to be _reduced_ when the domain of M is a set of + disjoint, non-adjacent closed fragments. + + NOTE: The NULL_KEY is not a valid key here. + + Author: brian.monahan@hpe.com + + (c) Copyright 2017 Hewlett Packard Enterprise Development LP + + 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. + + 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. +*******************************************************************************/ + +#include "utils.h" +#include "fragment.h" + +/******************************************************************************* + Classes and Types +*******************************************************************************/ + +typedef enum { + NULL_FRAG_MAP = 180, // Trivial fragment map i.e. single fragment mode. + LINEAR_LIST_FRAG_MAP, // Use Linear List implementation for fragment map + BINARY_TREE_FRAG_MAP // Use Binary Tree implementation for fragment map + } + FragMapKind_t; + + +// Fragment Maps +typedef struct fragmentMap FragMap_t; + + +/******************************************************************************* + Fragment Map Methods +*******************************************************************************/ +// Create a new fragment map (FragMap_t) +FragMap_t *new_FM(FragCls_t *fragCls, FragMapKind_t fragKind); + + +// Deallocate fragment map +void deallocate_FM(void *item); + + +// Add a point mapping to given fragment map +// - Adds the point to the mapping and then reduces the domain set +// by combining with adjacent fragments in the mapping. +// - Returns TRUE if addition was successful, FALSE otherwise. +Boolean_t addPoint_FM(FragMap_t *fragMap, Posn_t point, Object_t value); + + +// Add a consistent fragment to given fragment map +// - Adds the fragment to the mapping and then reduces the domain set +// by combining with adjacent fragments in the mapping. +// - Returns TRUE if addition was successful, FALSE otherwise. +Boolean_t addFragment_FM(FragMap_t *fragMap, Posn_t lower, Posn_t upper, Object_t value); + + +// Lookup covering fragment for a given point. +// - This determines the fragment that covers the given point, and returns it. +// - Returns NULL if not found +Frag_t *lookupFragment_FM(FragMap_t *fragMap, Posn_t point); + + +// Size of fragment map - i.e. number of disjoint fragments +int getSize_FM(FragMap_t *fragMap); + + +// Get the first fragment +// - Returns NULL if empty +Frag_t *getFirstFragment_FM(FragMap_t *fragMap); + + +// Enumerate fragment point mappings +// - Checks if map is locked (i.e. being enumerated). +// - Enumerates fragment objects in order. +// - Returns NULL, when completed. +// - Changes are locked out during enumeration. +Boolean_t isLocked_FM(FragMap_t *fragMap); // Checks if map is locked. +Frag_t *start_EnumMap_FM(FragMap_t *fragMap); // Initialises enumeration + locks mapping. +Frag_t *next_EnumMap_FM(FragMap_t *fragMap); // Gets the next fragment element (othwrwise NULL) +void stop_EnumMap_FM(FragMap_t *fragMap); // Stops the enumeration + unlocks mapping. + + +#endif diff --git a/hash_fusion/lib/hashFusion.c b/hash_fusion/lib/hashFusion.c new file mode 100644 index 0000000000..eb3465c78f --- /dev/null +++ b/hash_fusion/lib/hashFusion.c @@ -0,0 +1,580 @@ +/* hashFusion.c + + HashFusion Library + + Author: brian.monahan@hpe.com + + (c) Copyright 2017 Hewlett Packard Enterprise Development LP + + 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. + + 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. + +*/ + + +#include <stdio.h> +#include <stdlib.h> + +#include "utils.h" +#include "alloc.h" +#include "position.h" +#include "linkedList.h" +#include "stringbuffer.h" +#include "bytevector.h" +#include "matrix.h" +#include "fragment.h" +#include "fragmentMap.h" +#include "hashFusion.h" + + +//////////////////////////////////////////////////////////////////////////////// +// Hash Fusion types and structures +//////////////////////////////////////////////////////////////////////////////// +struct hashFusion { + CompareFn_t posnCompFn; // Position comparison function + AdjCompareFn_t adjCompFn; // Adjacency comparison function + HFuseAccum_t accumType; // Accumulation type + + HashSpec_t hashSpec; // Hash specifier + int dim; // Dimension of matrices (dependant upon hashSpec) + int digestLen; // Length of digest (dependant upon hashSpec) + + Digest_t *digest; // Final digest value -- weak reference (NO allocation) + int blockCount; // Current total of blocks + Key_t maxPosition; // Max position + HFuseState_t state; // Current state + FragMap_t *fragments; // Fragment map structure +}; + + +//////////////////////////////////////////////////////////////////////////////// +// Memory management +//////////////////////////////////////////////////////////////////////////////// +MemMgr_t *hashFusion_MemMgr = NULL; + + +//////////////////////////////////////////////////////////////////////////////// +// Static method prototypes +//////////////////////////////////////////////////////////////////////////////// +static void ensureMemMgmt(); + +// Mapping from to FragMapKind_t +static FragMapKind_t toFragMapKind(HFuseAccum_t accumKind); + +// Matrix combination utility +static Object_t matrixCombiner(Object_t a, Object_t b); + +// Extract result +static Boolean_t tryExtractResult(HFuse_t *hFuse); + +// Show utilities +static void initShowList(StringBuf_t *sBuf, ShowFn_t showFn); +static void showList(HFuse_t *hFuse); + + +//////////////////////////////////////////////////////////////////////////////// +// Methods +//////////////////////////////////////////////////////////////////////////////// +// Allocate a new HashFusion object. +// +// Parameters: +// CompareFn_t posnCompFn // Key comparison function +// AdjCompareFn_t adjCompFn // Adjacency comparison function +// HFuseAccum_t hfAccumType // HashFusion accumulation type (specifies method to accumulate) +// HashSpec_t hSpec // Hash function specifier +HFuse_t *new_HF(CompareFn_t posnCompFn, AdjCompareFn_t adjCompFn, HFuseAccum_t hfAccumType, HashSpec_t hSpec) { + // Ensure that the allocation structures exist + ensureMemMgmt(); + + HFuse_t *newHF = allocateObject_MM(hashFusion_MemMgr); + + FragCls_t *fragCls = new_FC(posnCompFn, adjCompFn, matrixCombiner, deallocateMatrix); + + + FragMapKind_t fragKind = toFragMapKind(hfAccumType); + + int digestLen = getDigestLength_DG(hSpec); + + newHF->posnCompFn = posnCompFn; + newHF->adjCompFn = adjCompFn; + newHF->accumType = hfAccumType; + newHF->hashSpec = hSpec; + newHF->dim = calcDimension(digestLen); // calculate dimension + newHF->digestLen = digestLen; + newHF->digest = NULL; // weak reference (NO allocation) + newHF->blockCount = 0; + newHF->maxPosition = 0; + newHF->state = Initial_HFuseState; + newHF->fragments = new_FM(fragCls, fragKind); + + return newHF; +} + + +// Deallocate/recycle Hash Fusion object +void deallocate_HF(HFuse_t *hFuse) { + + if (hFuse == NULL) return; + + // ensure that the allocation structures exist ... + ensureMemMgmt(); + + // deallocate fragments + deallocate_FM(hFuse->fragments); + + // nullify elements + NULLIFY_OBJ(hFuse, HFuse_t); + + deallocateObject_MM(hashFusion_MemMgr, sizeof(HFuse_t), hFuse); +} + + +// Resets the given hash fusion object +// - Giving NULL parameters implies reuse of existing parameters. +void reset_HF(HFuse_t *hFuse, CompareFn_t posnCompFn, AdjCompareFn_t adjCompFn, HFuseAccum_t accumType, HashSpec_t hSpec) { + req_NonNull(hFuse); + + // Ensure that the allocation structures exist + ensureMemMgmt(); + + // Set parameters + posnCompFn = (posnCompFn == NULL ? hFuse->posnCompFn : posnCompFn); + adjCompFn = (adjCompFn == NULL ? hFuse->adjCompFn : adjCompFn); + accumType = (accumType == ZERO_VAL ? hFuse->accumType : accumType); + hSpec = (hSpec == ZERO_VAL ? hFuse->hashSpec : hSpec); + + // deallocate fragment map + deallocate_FM(hFuse->fragments); + + FragCls_t *fragCls = new_FC(posnCompFn, adjCompFn, matrixCombiner, deallocateMatrix); + + FragMapKind_t fragKind = toFragMapKind(accumType); + + int digestLen = getDigestLength_DG(hSpec); + + hFuse->posnCompFn = posnCompFn; + hFuse->adjCompFn = adjCompFn; + hFuse->accumType = accumType; + hFuse->hashSpec = hSpec; + hFuse->dim = calcDimension(digestLen); // calculate dimension + hFuse->digestLen = digestLen; + hFuse->digest = NULL; // weak ref. + hFuse->blockCount = 0; + hFuse->maxPosition = 0; + hFuse->state = Initial_HFuseState; +} + +// Inspect current state ... +HFuseState_t getState_HF(HFuse_t *hFuse) { + req_NonNull(hFuse); + + return hFuse->state; +} + +// Show current state ... +char *showState_HF(HFuse_t *hFuse) { + req_NonNull(hFuse); + + // process current state + switch (hFuse->state) { + case NULL_HFuseState: return "NULL state"; + + case Initial_HFuseState: return "Initialised"; + case Partial_HFuseState: return "Partial"; + case Complete_HFuseState: return "Complete"; + + default: + diagnostic("hashFusion.showState_HF : Unknown state: %i", hFuse->state); + codeError_exit(); + } +} + +// Gets current accumulation type +HFuseAccum_t getAccumType_HF(HFuse_t *hFuse) { + req_NonNull(hFuse); + + return hFuse->accumType; +} + + +// Gets current Hash Spec +HashSpec_t getHashSpec_HF(HFuse_t *hFuse) { + req_NonNull(hFuse); + + return hFuse->hashSpec; +} + +// Gets Digest - if defined +// - This clones the mTree's digest object into given digest, dgst. +// - Returns TRUE only if digest was cloned. +Boolean_t getDigest_HF(Digest_t *dgst, HFuse_t *hFuse) { + req_NonNull(dgst); + req_NonNull(hFuse); + + if (hFuse->digest == NULL || hFuse->state != Complete_HFuseState) { + return FALSE; + } + else { + clone_DG(dgst, hFuse->digest); + + return TRUE; + } +} + +// Gets the total number of blocks so far. +int getNumBlocks_HF(HFuse_t *hFuse) { + req_NonNull(hFuse); + + return hFuse->blockCount; +} + +// Gets the number of fragments ... +int getNumFragments_HF(HFuse_t *hFuse) { + req_NonNull(hFuse); + + return getSize_FM(hFuse->fragments); +} + +// Show hash fragments info by appending to stringbuffer +// - uses specified show function showFn +// - set indent string +// - set compact display +// - set max length (if positive) +void show_HF(HFuse_t *hFuse, StringBuf_t *sBuf, ShowFn_t showFn) { + req_NonNull(hFuse); + req_NonNull(sBuf); + + showFn = (showFn == NULL ? show_Frag : showFn); + + initShowList(sBuf, showFn); + showList(hFuse); +} + +// show attributes +static char *show_indent = " "; // indent string +static Boolean_t show_compact_display = FALSE; +static int show_max_length = -1; + +void setShowIndent_HF(char * indent) { + show_indent = indent; +} + +void setShowCompact_HF(Boolean_t isCompact) { + show_compact_display = asBoolean(isCompact); +} + +void setShowMaxLength_HF(int maxLength) { + show_max_length = maxLength; +} + + +//////////////////////////////////////////////////////////////////////////////// +// Adding blocks, hashes and fragments +//////////////////////////////////////////////////////////////////////////////// + + +// Calculate hash from data block +Boolean_t calcDataHash_HF(Digest_t *digest, Key_t position, ByteVec_t *dataVec) { + req_NonNull(digest); + req_NonNull(dataVec); + req_Pos(position); // Strictly positive keys ... + + // Hash the data and place it in digest + return hashBV_DG(digest, dataVec); +} + + +// Adds data block into sequence +// - Position is 1-based and runs from 1 to max value K (with no gaps) +// - Returns TRUE if successful +Boolean_t addDataBlock_HF(HFuse_t *hFuse, Key_t position, ByteVec_t *dataVec) { + + req_NonNull(hFuse); + req_NonNull(dataVec); + req_Pos(position); // Strictly positive keys ... + + // Allocate a temporary digest + HashSpec_t hSpec = hFuse->hashSpec; + int dim = hFuse->dim; + int digestLen = hFuse->digestLen; + + Digest_t *tempDigest = new_DG(hSpec); + + // Hash the data and place it in digest + if (!hashBV_DG(tempDigest, dataVec)) { + deallocate_DG(tempDigest); + return FALSE; + } + + Boolean_t status = addDataHash_HF(hFuse, position, tempDigest); + + // deallocate temp. digest object + deallocate_DG(tempDigest); + return status; +} + +// Adds data hash into sequence +// - Position is 1-based and runs from 1 to max value K (with no gaps) +// - Returns TRUE if successful +Boolean_t addDataHash_HF(HFuse_t *hFuse, Key_t position, Digest_t *digest) { + return addDataRange_HF(hFuse, position, position, digest); +} + +// Adds data hash for range into sequence +// - Position is 1-based and runs from 1 to max value K (with no gaps) +// - Returns TRUE if successful +Boolean_t addDataRange_HF(HFuse_t *hFuse, Key_t lower, Key_t upper, Digest_t *digest) { + req_NonNull(hFuse); + req_NonNull(digest); + req_Pos(lower); // Strictly positive keys ... + req_Pos(upper); // Strictly positive keys ... + + + int dim = hFuse->dim; // dimension + int digestLen = hFuse->digestLen; // digest length + + ByteVec_t *tempBV = allocate_BV(digestLen+1); + + // extract hash value into byte vector from the digest ... + if (!getHashValue_DG(digest, tempBV)) { + diagnostic("addDataRange_HF: Digest could not be extracted to bytevector"); + codeError_exit(); + } + + // Allocate fresh matrix of appropriate dimension + Matrix_t *matrix = allocateTriMatrix(dim); + + // creating matrix version of hash digest value ... + // - This automatically deals with any padding + insertContent(matrix, tempBV); + + // deallocate the temporaries + deallocate_BV(tempBV); + + if (lower == upper) { + // Adding a single point ... + if (!addPoint_FM(hFuse->fragments, lower, (Object_t)matrix)) { + return FALSE; + } + } + else { + // Adding range ... + if (!addFragment_FM(hFuse->fragments, lower, upper, (Object_t)matrix)) { + return FALSE; + } + } + // updating blockCount and maxPosition ... + hFuse->blockCount += 1; + hFuse->maxPosition = keyMax(hFuse->posnCompFn, upper, hFuse->maxPosition); + + hFuse->state = Partial_HFuseState; + + // try to extract result ... + tryExtractResult(hFuse); + + return TRUE; +} + + +//////////////////////////////////////////////////////////////////////////////// +// Show functions for enumerated functions: +//////////////////////////////////////////////////////////////////////////////// +char *show_HFuseAccum(HFuseAccum_t val) { + switch (val) { + case DIRECT_ACCUM_HF: return "DIRECT_ACCUM_HF"; + case LINEAR_LIST_ACCUM_HF: return "LINEAR_LIST_ACCUM_HF"; + case TREE_SET_ACCUM_HF: return "TREE_SET_ACCUM_HF"; + default: + diagnostic("Unrecognised value (of type HFuseAccum_t): %i", val); + error_exit(); + } +} + +char *show_HFuseState(HFuseState_t val) { + switch (val) { + case NULL_HFuseState: return "NULL_HFuseState"; + case Initial_HFuseState: return "Initial_HFuseState"; + case Partial_HFuseState: return "Partial_HFuseStateF"; + case Complete_HFuseState: return "Complete_HFuseState"; + + default: + diagnostic("Unrecognised value (of type HFuseState_t): %i", val); + error_exit(); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// Static methods +//////////////////////////////////////////////////////////////////////////////// +static void ensureMemMgmt() { + if (hashFusion_MemMgr == NULL) { + hashFusion_MemMgr = new_MM(sizeof(HFuse_t)); + } +} + + +// Mapping from HFuseAccum_t to FragMapKind_t +static FragMapKind_t toFragMapKind(HFuseAccum_t accumKind) { + switch (accumKind) { + case DIRECT_ACCUM_HF: return LINEAR_LIST_FRAG_MAP; + case LINEAR_LIST_ACCUM_HF: return LINEAR_LIST_FRAG_MAP; + case TREE_SET_ACCUM_HF: return BINARY_TREE_FRAG_MAP; + + default: return LINEAR_LIST_FRAG_MAP; + } +} + + +// Matrix combination utility +static Object_t matrixCombiner(Object_t a, Object_t b) { + Matrix_t *matA = (Matrix_t *)a; + Matrix_t *matB = (Matrix_t *)b; + + int dim = getDimension(matA); + Matrix_t *matC = allocateTriMatrix(dim); + + multiply(matC, matA, matB); + return (Object_t)matC; +} + + +// Extract result +static Boolean_t tryExtractResult(HFuse_t *hFuse) { + req_NonNull(hFuse); + if (hFuse->maxPosition == hFuse->blockCount) { + + HashSpec_t hSpec = hFuse->hashSpec; + FragMap_t *fragMap = hFuse->fragments; + + // Should now have only one element in the fragments list ... + int curLength = getSize_FM(fragMap); + if (curLength != 1) { + diagnostic("hashFusion.addDataBlock_HF: Currently have %i fragments, should instead have only 1 when Complete", curLength); + codeError_exit(); + } + + // Fetch the top fragment ... + Frag_t *firstFrag = getFirstFragment_FM(fragMap); + + Matrix_t *fragMatrix = (Matrix_t *)firstFrag->value; + + int digestSize = getDigestLength_DG(hSpec); + + ByteVec_t *tempBV = allocate_BV(1+digestSize); + + // extracting content into bytevector from matrix + extractContent(tempBV, fragMatrix); + setLength_BV(tempBV, digestSize); + + // allocate or reset the digest object. + if (hFuse->digest == NULL) { + hFuse->digest = new_DG(hSpec); + } + else { + reset_DG(hFuse->digest, 0); + } + + // transfer hash value to digest ... + if (!setHashValue_DG(hFuse->digest, tempBV)) { + diagnostic("hashFusion.addDataBlock_HF: The operation setHashValue_DG failed for digest"); + codeError_exit(); + } + + // set state to Complete + hFuse->state = Complete_HFuseState; + + // finally deallocate temporary bytevector + deallocate_BV(tempBV); + + return TRUE; + } + else { + // hard reset of digest ... + deallocate_DG(hFuse->digest); + hFuse->digest = NULL; + + return FALSE; + } +} + + +/******************************************************************************* + Showing Hash Fusion fragments +*******************************************************************************/ +static StringBuf_t *curSBuf = NULL; +static ShowFn_t curShowFn = NULL; + +static void initShowList(StringBuf_t *sBuf, ShowFn_t showFn) { + req_NonNull(sBuf); + + curSBuf = sBuf; + curShowFn = showFn; +} + + +static void showList(HFuse_t *hFuse) { + req_NonNull(hFuse); + + int numFragments = getNumFragments_HF(hFuse); + + addItems_SB(curSBuf, "%sHFuse <state:%s, fragments:%i, blockCount:%i, maxPosition:%i, digest:%s>\n" + , show_indent + , showState_HF(hFuse) + , numFragments + , hFuse->blockCount + , hFuse->maxPosition + , showFingerprint_DG(hFuse->digest, 8) + ); + + if (show_compact_display || numFragments == 0) return; + + // Show fragments + + addItems_SB(curSBuf, "\n%sFragments (%i):\n", show_indent, numFragments); + + int count = 0; + + FragMap_t *fragMap = hFuse->fragments; + Frag_t *curFrag = start_EnumMap_FM(fragMap); + while (curFrag != NULL) { + addItems_SB(curSBuf, "%s %i: %s\n", show_indent, count+1, curShowFn(curFrag)); + + curFrag = next_EnumMap_FM(fragMap); + count += 1; + + if (count > 100) { + diagnostic("showList: count exceeded limit %i, Seems to be a loop ...", count); + error_exit(); + } + } + addItems_SB(curSBuf, "%sEnd.\n", show_indent); + + // check that the actual number of fragments (count) and the calculated number of fragments (numFragments) agree ... + if (count != numFragments) { + print_SB(curSBuf); + diagnostic("showList : NumFragments = %i, actual num. fragments = %i", numFragments, count); + error_exit(); + } + //stop_EnumMap_FM(fragMap); +} diff --git a/hash_fusion/lib/hashFusion.h b/hash_fusion/lib/hashFusion.h new file mode 100644 index 0000000000..699c040ded --- /dev/null +++ b/hash_fusion/lib/hashFusion.h @@ -0,0 +1,175 @@ +#ifndef __HASHFUSION_H__ +#define __HASHFUSION_H__ + +/******************************************************************************* + hashFusion.h + + HashFusion Library + + Author: brian.monahan@hpe.com + + (c) Copyright 2017 Hewlett Packard Enterprise Development LP + + 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. + + 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. +*******************************************************************************/ + +#include "utils.h" +#include "bytevector.h" +#include "stringbuffer.h" +#include "fragment.h" +#include "hashlib.h" + + +/******************************************************************************* + Hash Fusion object type + - This corresponds to a Merkle Hash Tree +*******************************************************************************/ +typedef struct hashFusion HFuse_t; + + +/******************************************************************************* + Hash Fusion Accumulation Type + + + Provides implmentation to accumulate hash objects in sequence. + + + Types of accumulation structure: + + - Free Form: Accumulate hashes directly in sequence. Effectively combines hashes + as given with no gaps. + + - Linear List: Builds a linear list of fragments. Useful for small numbers of + blocks. + + - Balanced Binary Tree: Builds a self-balancing tree structure (with O(lg N) + access and insert behaviour). This is a scalable solution suitable for + large files. + +*******************************************************************************/ +typedef enum { + DIRECT_ACCUM_HF = 100, // Direct accumulation structure (i.e. only accumulate directly at either end). + LINEAR_LIST_ACCUM_HF, // Linear list accumulation structure + TREE_SET_ACCUM_HF // Balanced binary tree accumulation structure + } + HFuseAccum_t; + + +/******************************************************************************* + Hash Fusion state +*******************************************************************************/ +// Hash Fusion state values +// - a complete sequence means there are no missing blocks (i.e. no gaps between 0 and current max position). +// - even if we have a complete sequence, there could still be more input. +// +// Operations cycle: init->partial <-> complete +typedef enum { + NULL_HFuseState = 10, // Not a valid state (i.e. uninitialised) + Initial_HFuseState, // Initial state (empty sequence) + Partial_HFuseState, // Partial state (partial sequence) - in progress/under construction + Complete_HFuseState // Complete state (completed initial sequence, but there could be more input ...) + } + HFuseState_t; + + +/******************************************************************************* + Methods +*******************************************************************************/ +// Allocate a new HashFusion object. +// Parameters: +// CompareFn_t keyCompFn // Key comparison function +// AdjCompareFn_t adjCompFn // Adjacency comparison function +// HFuseAccum_t hfAccumType // HashFusion accumulation type (specifies method to accumulate) +// HashSpec_t hSpec // Hash function specifier +HFuse_t *new_HF(CompareFn_t keyCompFn, AdjCompareFn_t adjCompFn, HFuseAccum_t hfAccumType, HashSpec_t hSpec); + +// Deallocate/recycle HashFusion object +void deallocate_HF(HFuse_t *hFuse); + +// Resets the given HashFusion object +// - Giving NULL parameters implies reuse of existing parameters. +void reset_HF(HFuse_t *hFuse, CompareFn_t keyCompFn, AdjCompareFn_t adjCompFn, HFuseAccum_t hfAccumType, HashSpec_t hSpec); + +// Inspect current state ... +HFuseState_t getState_HF(HFuse_t *hFuse); + +// Show current state ... +char *showState_HF(HFuse_t *hFuse); + +// Gets current accumulation type +HFuseAccum_t getAccumType_HF(HFuse_t *hFuse); + +// Gets current Hash Spec +HashSpec_t getHashSpec_HF(HFuse_t *hFuse); + +// Gets Digest - if defined +// - This clones the digest object into given digest, dgst. +// - Returns TRUE only if digest was cloned. +Boolean_t getDigest_HF(Digest_t *dgst, HFuse_t *hFuse); + +// Gets the total number of blocks so far. +int getNumBlocks_HF(HFuse_t *hFuse); + +// Gets the number of fragments ... +int getNumFragments_HF(HFuse_t *hFuse); + +//////////////////////////////////////////////////////////////////////////////// +// Hash joining ... +//////////////////////////////////////////////////////////////////////////////// + +// Calculate hash from data block +Boolean_t calcDataHash_HF(Digest_t *digest, Key_t position, ByteVec_t *dataVec); + +// Adds data block into sequence +// - Position is 1-based and runs from 1 to max value K (with no gaps) +// - Returns TRUE if successful +Boolean_t addDataBlock_HF(HFuse_t *hFuse, Key_t position, ByteVec_t *dataVec); + +// Adds data hash into sequence +// - Position is 1-based and runs from 1 to max value K (with no gaps) +// - Returns TRUE if successful +Boolean_t addDataHash_HF(HFuse_t *hFuse, Key_t position, Digest_t *digest); + +// Adds data hash for range into sequence +// - Position is 1-based and runs from 1 to max value K (with no gaps) +// - Returns TRUE if successful +Boolean_t addDataRange_HF(HFuse_t *hFuse, Key_t lower, Key_t upper, Digest_t *digest); + + +//////////////////////////////////////////////////////////////////////////////// +// Show functions +//////////////////////////////////////////////////////////////////////////////// +// Show hash fragments info by appending to stringbuffer +// - uses specified show function showFn +// - set indent string +// - set compact display +// - set max length (if positive) +void show_HF(HFuse_t *hFuse, StringBuf_t *sbuf, ShowFn_t showFn); +void setShowIndent_HF(char * indent); +void setShowCompact_HF(Boolean_t isCompact); +void setShowMaxLength_HF(int maxLength); + +// Show functions for enumerated functions: +char *show_HFuseAccum(HFuseAccum_t val); +char *show_HFuseState(HFuseState_t val); + +#endif diff --git a/hash_fusion/lib/hashlib.c b/hash_fusion/lib/hashlib.c new file mode 100644 index 0000000000..f292fccc7b --- /dev/null +++ b/hash_fusion/lib/hashlib.c @@ -0,0 +1,719 @@ +/******************************************************************************* + hashlib.c + + Management wrappers for OpenSSL + - Uses OpenSSL libraries to provide standard hash functions + + Author: brian.monahan@hpe.com + + (c) Copyright 2017 Hewlett Packard Enterprise Development LP + + 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. + + 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. + +*******************************************************************************/ +#include <openssl/evp.h> + +#include "utils.h" +#include "bytevector.h" +#include "stringbuffer.h" +#include "alloc.h" + +#include "hashlib.h" + + +/******************************************************************************* + Hash Digest +*******************************************************************************/ +// The hashDigest object (Digest_t) encapsulates all infomation needed to coordinate +// hashing operations. +struct hashDigest { + ByteVec_t *result; // Resulting hash-digest (as a bytevector) + int bytesHashed; // Number of bytes hashed + HashSpec_t hashSpec; // Hash specification - e.g. sha256 etc. + Hashstate_t hashState; // Phase of hash operations. + + // OpenSSL components + const EVP_MD *md; // Internal OpenSSL message digest specifier + EVP_MD_CTX *mdctx; // Internal OpenSSL message digest content +}; + + +// Static method prototypes +static unsigned int digestBytes(const EVP_MD *md, int length, Byte_t *bytes, Byte_t *digest); +static EVP_MD_CTX *contextInit(const EVP_MD *md); +static Boolean_t processBlock(EVP_MD_CTX *mdctx, int length, Byte_t *bytes); +static unsigned int digestFinal(EVP_MD_CTX *mdctx, Byte_t *digest); + +static Boolean_t isHashSpec(HashSpec_t hSpec); + +static const EVP_MD *getMD(HashSpec_t hSpec); +static void ensureMemMgmt(); +static void dispose_DG(void *obj); + + +// hashDigest Memory Management +MemMgr_t *hashDigest_MemMgr = NULL; + + +// Allocates a hash digest object +Digest_t *new_DG(HashSpec_t hSpec) { + if (!isHashSpec(hSpec)) { + diagnostic("hashlib.new_DG: Expected a HashSpec value - instead, got (%i)", hSpec); + codeError_exit(); + } + + // Ensure that the allocation structure has been setup. + ensureMemMgmt(); + + // allocate digest object + Digest_t *dgst = allocateObject_MM(hashDigest_MemMgr); + + dgst->result = allocate_BV(0); // allocate byte vector (no local memory) + dgst->bytesHashed = 0; + dgst->hashSpec = hSpec; + dgst->hashState = HST_READY; + + dgst->md = getMD(hSpec); // message digest info. corresponding to hSpec + dgst->mdctx = NULL; // message digest context + + // return allocated digest object + return dgst; +} + + +// Deallocates hash digest object +void deallocate_DG(Digest_t *dgst) { + if (dgst == NULL) return; + + // Ensure that the allocation structure has been setup. + ensureMemMgmt(); + + // deallocate the byte vector ... + deallocate_BV(dgst->result); + + // check for any EVP_MD_CTX object + if (dgst->mdctx != NULL) { + // releases any EVP_MD_CTX object + EVP_MD_CTX_destroy(dgst->mdctx); + dgst->md = NULL; + dgst->mdctx = NULL; + } + + // recycle the digest object on the allocation structure + deallocateObject_MM(hashDigest_MemMgr, sizeof(Digest_t), dgst); +} + + +// Resets hash digest object +// - no allocation performed ... +// - results in a digest object in ready state. +// - if hSpec == 0, then reuse existing hSpec value. +void reset_DG(Digest_t *dgst, HashSpec_t hSpec) { + req_NonNull(dgst); + + if (hSpec == 0) { + hSpec = dgst->hashSpec; + } + + if (!isHashSpec(hSpec)) { + diagnostic("hashlib.new_DG: Expected a HashSpec value - instead, got (%i)", hSpec); + codeError_exit(); + } + + // check for any EVP_MD_CTX object + if (dgst->mdctx != NULL) { + // releases EVP_MD_CTX object + EVP_MD_CTX_destroy(dgst->mdctx); + dgst->md = NULL; + dgst->mdctx = NULL; + } + + // reinitialise dgst + reset_BV(dgst->result); + + dgst->bytesHashed = 0; + dgst->hashSpec = hSpec; + dgst->hashState = HST_READY; + + dgst->md = getMD(hSpec); // gets the message digest info. corresponding to hSpec + dgst->mdctx = NULL; +} + + +// Gets the number of bytes hashed so far +int getBytesHashed_DG(Digest_t *dgst) { + req_NonNull(dgst); + + return dgst->bytesHashed; +} + + +// Gets the current hash spec value. +HashSpec_t getHashSpec_DG(Digest_t *dgst) { + req_NonNull(dgst); + + return dgst->hashSpec; +} + +// Extracts nominal string of the hash spec value +const char *showHashSpec_DG(HashSpec_t hSpec) { + switch (hSpec) { + case HSP_SHA224: return "SHA-224"; + case HSP_SHA256: return "SHA-256"; + case HSP_SHA384: return "SHA-384"; + case HSP_SHA512: return "SHA-512"; + case HSP_RIPEMD160: return "RIPEMD-160"; + + default: + diagnostic("hashlib.showHashSpec_DG: Unrecognised hash-spec (%i)", hSpec); + codeError_exit(); + } +} + + +// Digest length (in bytes) +int getDigestLength_DG(HashSpec_t hSpec) { + return ((hSpec % 1000) / 8); +} + + +// Extracts the (binary) hash value from the current digest and appends to the given bytevector ... +// - The digest must have already been finalised. +// - The result is TRUE if the digest hash value was appended. +Boolean_t getHashValue_DG(Digest_t *dgst, ByteVec_t *resultBV) { + req_NonNull(dgst); + req_NonNull(resultBV); + + if (dgst->hashState != HST_FINAL) { + return FALSE; + } + else { + appendInto_BV(resultBV, dgst->result); + + return TRUE; + } +} + + +// Sets the (binary) hash value of the digest from the given bytevector ... +// - The length of the (binary) data must exactly match the required digest size. +// - THe digest state should be Ready or Init +// - If successful, the digest state becomes Final. +// - The result is TRUE only if the digest hash value was successfully set. +Boolean_t setHashValue_DG(Digest_t *dgst, ByteVec_t *sourceBV) { + req_NonNull(dgst); + req_NonNull(sourceBV); + + int srcLength = getLength_BV(sourceBV); + int digestSize = getDigestLength_DG(dgst->hashSpec); + + if (srcLength != digestSize) { + diagnostic("hashlib.setHashValue_DG: Bytevector provided %i bytes, but expected %i bytes instead", srcLength, digestSize); + codeError_exit(); + } + + if (dgst->hashState != HST_INIT && dgst->hashState != HST_READY) { + + return FALSE; + } + else { + wipe_BV(dgst->result); + appendInto_BV(dgst->result, sourceBV); + + dgst->hashState = HST_FINAL; + + return TRUE; + } +} + + +// Checks that the digests are equal in value ... +// - Both must be as _equally_ defined i.e. both = NULL or both != NULL +Boolean_t isEqual_DG(Digest_t *dgst1, Digest_t *dgst2) { + if (dgst1 == NULL) { + return (dgst2 == NULL); + } + else if (dgst2 == NULL) { + // i.e. dgst1 != NULL and dgst2 == NULL + return FALSE; + } + + // dgst1 != NULL and dgst2 != NULL + return isEqual_BV(dgst1->result, dgst2->result); +} + + +// Clones a digest value from source digest to destination digest. +// - the source digest state should be final. +// - Destination digest state becomes final. +// - Result is false if no data transferred - otherwise true. +Boolean_t clone_DG(Digest_t *dest, Digest_t *source) { + req_NonNull(dest); + req_NonNull(source); + + if (source->hashState != HST_FINAL) { + return FALSE; + } + else { + clone_BV(dest->result, source->result); + dest->hashState = HST_FINAL; + return TRUE; + } +} + + +// Extracts a hex string of the hash value +// - the output string is volatile (i.e. could change ...) +static char hashBuffer[2 * MAX_DIGEST_SIZE + 1]; +char *showHexHashValue_DG(Digest_t *dgst) { + if (dgst == NULL) return NULL_STR; + + char *sPtr = hashBuffer; + + int len = getLength_BV(dgst->result); + Byte_t *bytes = getContent_BV(dgst->result); + + // check for null content ... + if (bytes == NULL) { + return NULL_STR; + } + + // pack content as hex into hashBuffer + for(int i = 0; i < len; i++) { + sprintf(sPtr, "%02x", bytes[i]); + sPtr += 2; + } + + return hashBuffer; +} + + +// Shows a short fingerprint of the hash value +// - the output string is volatile +// - 4 <= fpLength <= 16, with default value: 7 +// - the output string is volatile +char *showFingerprint_DG(Digest_t *dgst, int fpLength) { + if (dgst == NULL) return NULL_STR; + + return showFingerprint_BV(dgst->result, fpLength); +} + + +// Extracts the current state +// - getHashState_DG produces current state value +// - showHashState_DG produces a print string +Hashstate_t getHashState_DG(Digest_t *dgst) { + req_NonNull(dgst); + + return dgst->hashState; +} + +char *showHashState_DG(Digest_t *dgst) { + switch (dgst->hashState) { + case HST_READY: return "Ready"; + case HST_INIT: return "Initialised"; + case HST_PROCESS: return "Processing"; + case HST_FINAL: return "Finalised"; + + default: + return "<Unknown hash-state>"; + } +} + + +// Hash an entire byte vector in a single step. +// - The digest state should be ready. +// - Hashes the input data and computes the final hashvalue +// - The hashValue is placed into the Digest_t object. +// - The result indicates if the hash operation was successful. +// + If successful, the hash state becomes HST_FINAL. +// + Otherwise, remains unchanged. +Boolean_t hashBV_DG(Digest_t *dgst, ByteVec_t *dataInput) { + + req_NonNull(dataInput); + + Hashstate_t hState = dgst->hashState; + if (hState != HST_READY) { + return FALSE; + } + + int dataLen = getLength_BV(dataInput); + Byte_t *data = getContent_BV(dataInput); + + // Ensure that the dgst result has sufficient space for digest result + ensureCapacity_BV(dgst->result, MAX_DIGEST_SIZE+1); + + // calculate the hash value from given bytes ... + int mdLen = digestBytes(dgst->md, dataLen, data, getContent_BV(dgst->result)); + + if (mdLen > 0) { + // set the length of the bytevector ... + setLength_BV(dgst->result, mdLen); + + // set the bytesHashed to dataLen + dgst->bytesHashed = dataLen; + + // set hashState + dgst->hashState = HST_FINAL; + return TRUE; + } + else { + // An error occurred ... + + // Reset the digest result vector ... + reset_BV(dgst->result); + return FALSE; + } +} + + +/******************************************************************************* + Hashing sequences of data blocks ... + - The data blocks are themselves wrapped within bytevectors. + - These do not "fail"/"abort" - instead, status is reported by return value. +*******************************************************************************/ + +// Initialise the Digest_t object ready to hash a sequence of data blocks. +// - the hashstate starts in HST_READY and ends in HST_INIT +Boolean_t hashInit_DG(Digest_t *dgst) { + req_NonNull(dgst); + + // check hash state ... + if (dgst->hashState != HST_READY) { + return FALSE; + } + + // create and initialise the context ... + dgst->mdctx = contextInit(dgst->md); + + // set hash state + dgst->hashState = HST_INIT; + + return TRUE; +} + + +// Add a data block byte vector to current digest. +// - The hashstate starts in either state HST_INIT or HST_PROCESS and transitions to HST_PROCESS +Boolean_t addOneBlock_DG(Digest_t *dgst, ByteVec_t *dataInput) { + req_NonNull(dgst); + req_NonNull(dataInput); + + // check hash state .. + if (dgst->hashState != HST_INIT && dgst->hashState != HST_PROCESS) { + return FALSE; + } + + int dataLen = getLength_BV(dataInput); + Byte_t *data = getContent_BV(dataInput); + + // Ensure that the dgst result has sufficient space for digest result + ensureCapacity_BV(dgst->result, MAX_DIGEST_SIZE+1); + + // calculate the hash value ... + int mdLen = digestBytes(dgst->md, dataLen, data, getContent_BV(dgst->result)); + + if (mdLen > 0) { + // set the length of the bytevector ... + setLength_BV(dgst->result, mdLen); + + // add dataLen to the bytesHashed + dgst->bytesHashed += dataLen; + + // set hashState + dgst->hashState = HST_PROCESS; + return TRUE; + } + else { + // An error occurred ... + + // wipe the result ... + reset_BV(dgst->result); + + return FALSE; + } +} + + +// Hashes the given sequence of data blocks, where each data block is +// contained in a bytevector. +// - The hashstate starts in either state HST_INIT or HST_PROCESS and transitions to HST_PROCESS +Boolean_t hashBlocks_DG(Digest_t *dgst, int length, ByteVec_t *blocks[]) { + req_NonNull(dgst); + + // check hash state ... + if (dgst->hashState != HST_INIT && dgst->hashState != HST_PROCESS) { + return FALSE; + } + + ByteVec_t *curVec = NULL; + int dataLen = 0; + + for (int i = 0; i<length; i++) { + curVec = blocks[i]; + + if (curVec != NULL) { + dataLen = getLength_BV(curVec); + + if (dataLen > 0) { + if (processBlock(dgst->mdctx, dataLen, getContent_BV(curVec))) { + dgst->bytesHashed += dataLen; + } + else { + + } + } + } + } + + // set hash state + dgst->hashState = HST_PROCESS; + + return TRUE; +} + +// Finalise the current sequence ... +// - The final hash-value is computed. +// - The hashstate should be HST_PROCESS and transitions to HST_FINAL. +Boolean_t hashFinal_DG(Digest_t *dgst) { + req_NonNull(dgst); + + if (dgst->hashState == HST_FINAL) { + return TRUE; + } + + // check hash state ... + if (dgst->hashState != HST_PROCESS) { + return FALSE; + } + + // extract the hash value ... + int mdLen = digestFinal(dgst->mdctx, getContent_BV(dgst->result)); + + if (mdLen > 0) { + // set the length of the bytevector ... + setLength_BV(dgst->result, mdLen); + + // set hashState + dgst->hashState = HST_FINAL; + return TRUE; + } + else { + // An error occurred ... + + // wipe the result ... + reset_BV(dgst->result); + + // set hashState + dgst->hashState = HST_FINAL; + + return FALSE; + } +} + + +/*******************************************************************************l + Wrappers for standard hash digest calc. using OpenSSL digest algorithms +*******************************************************************************/ + +// Single-shot hashing of a single block of data +static unsigned int digestBytes(const EVP_MD *md, int length, Byte_t *bytes, Byte_t *digest) { + req_NonNull(digest); + + EVP_MD_CTX *mdctx = contextInit(md); + + // Hash the data ... + if (1 != EVP_DigestUpdate(mdctx, bytes, length)) { + EVP_MD_CTX_destroy(mdctx); + + // ensure safe digest value + digest[0] = 0; + return 0; + } + + return digestFinal(mdctx, digest); +} + + +// Generate and initialise the digest +static EVP_MD_CTX *contextInit(const EVP_MD *md) { + EVP_MD_CTX *mdctx; + + // Set up digest context + mdctx = EVP_MD_CTX_create(); + + // Bind message digest to context + EVP_DigestInit_ex(mdctx, md, NULL); + + // return the context + return mdctx; +} + + +static Boolean_t processBlock(EVP_MD_CTX *mdctx, int length, Byte_t *bytes) { + return asBoolean( EVP_DigestUpdate(mdctx, bytes, length) ); +} + + +static unsigned int digestFinal(EVP_MD_CTX *mdctx, Byte_t *digest) { + unsigned int md_len = 0; + + // Finalise + EVP_DigestFinal_ex(mdctx, digest, &md_len); + EVP_MD_CTX_destroy(mdctx); + + // return the length + return md_len; +} + + +/******************************************************************************* + Auxilliaries +*******************************************************************************/ +static Boolean_t isHashSpec(HashSpec_t hSpec) { + switch (hSpec) { + case HSP_SHA224: // FALLTHROUGH + case HSP_SHA256: // FALLTHROUGH + case HSP_SHA384: // FALLTHROUGH + case HSP_SHA512: // FALLTHROUGH + case HSP_RIPEMD160: return TRUE; + + default: + return FALSE; + } +} + + +static const EVP_MD *getMD(HashSpec_t hSpec) { + switch (hSpec) { + case HSP_SHA224: return EVP_sha224(); + case HSP_SHA256: return EVP_sha256(); + case HSP_SHA384: return EVP_sha384(); + case HSP_SHA512: return EVP_sha512(); + case HSP_RIPEMD160: return EVP_ripemd160(); + + default: + diagnostic("hashlib.getMD: Unrecognised hash-spec (%i)", hSpec); + codeError_exit(); + } +} + +// setup allocation structure +static void ensureMemMgmt() { + if (hashDigest_MemMgr == NULL) { + hashDigest_MemMgr = new_MM(sizeof(Digest_t)); + setFinaliser_MM(hashDigest_MemMgr, dispose_DG); + } +} + +// disposal of digest memory ... +static void dispose_DG(void *obj) { + if (obj == NULL) return; + + Digest_t *dgst = (Digest_t *)obj; + + if (dgst->mdctx != NULL) { + // releases the EVP_MD_CTX objects + EVP_MD_CTX_destroy(dgst->mdctx); + dgst->mdctx = NULL; + } + + // free the Digest_t object itself. + free(dgst); +} + + +/* + +//unsigned int digestBlocks(const EVP_MD *md, Byte_t *blocks[], int maxBlocks, int totalChars, Byte_t *digest); +//static int calcTotalBlocks(Byte_t *blocks[], int maxBlocks); + +// Single-shot hash processing +unsigned int digestBytes(const EVP_MD *md, ByteVec_t *bytes, Byte_t *md_value) { + EVP_MD_CTX *mdctx; + unsigned int md_len = 0; + + // Set up context + mdctx = EVP_MD_CTX_create(); + + // Bind message digest to context + EVP_DigestInit_ex(mdctx, md, NULL); + + // Hash the data + EVP_DigestUpdate(mdctx, getContent_BV(bytes), getLength_BV(bytes)); + + // Finalise + EVP_DigestFinal_ex(mdctx, md_value, &md_len); + EVP_MD_CTX_destroy(mdctx); + + return md_len; +} + + +// Processes a seqeunce of blocks (same size = BLOCKSIZE, except possibly the last one) +unsigned int digestBlocks(const EVP_MD *md, Byte_t *blocks[], int maxBlocks, int totalChars, Byte_t *md_value) { + EVP_MD_CTX *mdctx; + unsigned int md_len = 0; + + int totalBlocks = calcTotalBlocks(blocks, maxBlocks); + + size_t charsRemaining = totalChars; + size_t thisBlkSz = 0; + void *blockPtr = NULL; // current ptr to data block + + // Set up context + mdctx = EVP_MD_CTX_create(); + + // Bind message digest to context + EVP_DigestInit_ex(mdctx, md, NULL); + + // hash all blocks + // - assumes that all but the last block has size BLOCKSIZE. + for (int posn = 0; posn < totalBlocks && charsRemaining > 0; posn++) { + blockPtr = (void *)blocks[posn]; + thisBlkSz = (charsRemaining <= BLOCKSIZE ? charsRemaining : BLOCKSIZE); + EVP_DigestUpdate(mdctx, blockPtr, thisBlkSz); + charsRemaining -= thisBlkSz; + } + + // Finalise + EVP_DigestFinal_ex(mdctx, md_value, &md_len); + EVP_MD_CTX_destroy(mdctx); + + return md_len; +} + + +static int calcTotalBlocks(Byte_t *blocks[], int maxBlocks) { +// count the number of non-null blocks + int totalBlocks = 0; + for (int i = 0; i < maxBlocks; i++) { + if (blocks[i] != NULL) { + totalBlocks++; + } + } + + return totalBlocks; +} +*/ diff --git a/hash_fusion/lib/hashlib.h b/hash_fusion/lib/hashlib.h new file mode 100644 index 0000000000..23fc8bfe69 --- /dev/null +++ b/hash_fusion/lib/hashlib.h @@ -0,0 +1,185 @@ +#ifndef __HASHLIB_H__ +#define __HASHLIB_H__ + +/******************************************************************************* + hashlib.h + + Some management wrappers for OpenSSL + - Uses OpenSSL libraries to provide standard hash functions + + Author: brian.monahan@hpe.com + + (c) Copyright 2017 Hewlett Packard Enterprise Development LP + + 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. + + 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. +*******************************************************************************/ + +#include "utils.h" +#include "bytevector.h" + +// Hash digest objects ... +typedef struct hashDigest Digest_t; + +// Hash spec codes ... +// - Note: size of digest is encoded: (HSP_SHA384 % 1000) == 384 bits +typedef enum { + HSP_NULL = 1110000, // Represents null/undefined hashspec + HSP_SHA224 = 1110224, // Represents sha 224 + HSP_SHA256 = 1110256, // Represents sha 256 + HSP_SHA384 = 1110384, // Represents sha 384 + HSP_SHA512 = 1110512, // Represents sha 512 + HSP_RIPEMD160 = 1111160 // Represents ripemd 160 + } + HashSpec_t; + + +// Hash operations state +// - The std operations cycle is: ready->init->proc->...->final +// - There is also an error state - which can only be cleared by reset_DG. +typedef enum { + HST_READY = 60, // Ready (default) state + HST_INIT, // Digest initialised + HST_PROCESS, // Digest in process + HST_FINAL, // Digest finalised - hash-value available. + HST_ERROR // Error state ... digest needs reset ... + } + Hashstate_t; + + +// Maximum Digest Size (in bytes) +// - larger than that specified by OpenSSL +#define MAX_DIGEST_SIZE 128 + + +// Allocates a hash digest object +Digest_t *new_DG(HashSpec_t hSpec); + + +// Deallocates hash digest object +void deallocate_DG(Digest_t *dgst); + + +// Resets hash digest object +// - No allocation performed ... +// - Results in a digest object in ready state. +// - If hSpec = 0, reuse existing hSpec value. +void reset_DG(Digest_t *dgst, HashSpec_t hSpec); + + +// Gets the number of bytes hashed so far. +int getBytesHashed_DG(Digest_t *dgst); + + +// Gets the current hash spec value. +HashSpec_t getHashSpec_DG(Digest_t *dgst); + + +// Extracts nominal string of the hash spec value +const char *showHashSpec_DG(HashSpec_t hSpec); + + +// Digest length (in bytes) +int getDigestLength_DG(HashSpec_t hSpec); + + +// Checks that the digests are equal in value ... +// - Both must be equally defined i.e. both = NULL or both != NULL +Boolean_t isEqual_DG(Digest_t *dgst1, Digest_t *dgst2); + + +// Clones a digest value from source digest to destination digest. +// - the source digest state should be final. +// - Destination digest state becomes final. +// - Result is false if no data transferred - otherwise true. +Boolean_t clone_DG(Digest_t *dest, Digest_t *source); + + +// Extracts the (binary) hash value from the current digest and appends to the given bytevector ... +// - The digest must have already been finalised. +// - The result is TRUE if the digest hash value was appended. +Boolean_t getHashValue_DG(Digest_t *dgst, ByteVec_t *resultBV); + + +// Sets the (binary) hash value of the digest from the given bytevector ... +// - The length of the (binary) data must exactly match the required digest size. +// - THe digest state should be Ready or Init +// - If successful, the digest state becomes Final. +// - The result is TRUE only if the digest hash value was successfully set. +Boolean_t setHashValue_DG(Digest_t *dgst, ByteVec_t *sourceBV); + +// Extracts a hex string of the hash value +// - the output string is volatile +char *showHexHashValue_DG(Digest_t *dgst); + + +// Shows a short fingerprint of the hash value +// - the output string is volatile +// - 4 <= fpLength <= 16, with default value: 7 +char *showFingerprint_DG(Digest_t *dgst, int fpLength); + + +// Extracts the current state +// - getHashState_DG produces current state value +// - showHashState_DG produces a print string +Hashstate_t getHashState_DG(Digest_t *dgst); +char *showHashState_DG(Digest_t *dgst); + + +// Hash an entire byte vector in a single step. +// - The digest state should be ready. +// - Hashes the input data and computes the final hashvalue +// - The hashValue is placed into the Digest_t object. +// - The result indicates if the hash operation was successful. +// + If successful, the hash state becomes HST_FINAL. +// + Otherwise, remains unchanged. +Boolean_t hashBV_DG(Digest_t *dgst, ByteVec_t *dataInput); + + +/******************************************************************************* + Hashing sequences of data blocks ... + - The data blocks are themselves wrapped within bytevectors. +*******************************************************************************/ + +// Initialise the Digest_t object ready to hash a sequence of data blocks. +// - the hashstate starts in HST_READY and ends in HST_INIT +Boolean_t hashInit_DG(Digest_t *dgst); + + +// Add a data block byte vector to current digest. +// - The hashstate starts in either state HST_INIT or HST_PROCESS and transitions to HST_PROCESS +Boolean_t addOneBlock_DG(Digest_t *dgst, ByteVec_t *dataInput); + + +// Hash a given sequence of data blocks, where each block is contained in a bytevector. +// - The hashstate starts in either state HST_INIT or HST_PROCESS and transitions to HST_PROCESS +Boolean_t hashBlocks_DG(Digest_t *dgst, int length, ByteVec_t *blocks[]); + + +// Finalise the current sequence ... +// - The final hash-value is computed. +// - The hashstate should be HST_PROCESS or HST_FINAL and transitions t0 HST_FINAL. +Boolean_t hashFinal_DG(Digest_t *dgst); + + +#endif diff --git a/hash_fusion/lib/linearMap.c b/hash_fusion/lib/linearMap.c new file mode 100644 index 0000000000..2ccc5a7ebc --- /dev/null +++ b/hash_fusion/lib/linearMap.c @@ -0,0 +1,321 @@ +/* linearMap.c + + Simple indexed mapping. + + Author: brian.monahan@hpe.com + + (c) Copyright 2017 Hewlett Packard Enterprise Development LP + + 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. + + 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. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "utils.h" +#include "alloc.h" +#include "linearMap.h" + + +typedef struct mapCell MapCell_t; + + +struct linearMap { + int size; + VoidFn_t finalObjFn; + MapCell_t *firstCell; +}; + +struct mapCell { + unsigned long key; + void *content; + MapCell_t *nextCell; +}; + + +// Local prototypes +static MapCell_t *allocateCell(); +static void deallocateCell(MapCell_t *cell); + +static MapCell_t *findCellByKey(LinearMap_t *lMap, unsigned long key); +static void insertNewCell(LinearMap_t *lMap, unsigned long key, void *entry); + +// generates new LinearMap_t +LinearMap_t *new_LM() { + + LinearMap_t *newLmap = ALLOC_OBJ(LinearMap_t); + + newLmap->size = 0; + newLmap->finalObjFn = nullVoidFn; + newLmap->firstCell = NULL; + + return newLmap; +} + + +// Deallocate linear map +void deallocate_LM(void *item) { + if (item == NULL) return; + + LinearMap_t *lMap = (LinearMap_t *)item; + + clear_LM(lMap); + + NULLIFY_OBJ(lMap, LinearMap_t); + + free(lMap); +} + +// Set object finaliser function ... +// - No finalisation happens for data items unless this is set. +void setFinaliser_LM(LinearMap_t *lMap, VoidFn_t finalObjFn) { + req_NonNull(lMap); + + finalObjFn = (finalObjFn == NULL ? nullVoidFn : finalObjFn); + + lMap->finalObjFn = finalObjFn; +} + +void *getEntry_LM(LinearMap_t *lMap, unsigned long key) { + req_NonNull(lMap); + + MapCell_t *curCell = lMap->firstCell; + unsigned long curKey; + + while (curCell != NULL) { + curKey = curCell->key; + if (curKey == key) { + // SUCCESS! + return curCell->content; + } + else if (curKey > key) { + // FAILED: NOT FOUND + return NULL; + } + + curCell = curCell->nextCell; + } + + // FAILED: NOT FOUND + return NULL; +} + + +void addEntry_LM(LinearMap_t *lMap, unsigned long key, void *entry) { + req_NonNull(lMap); + req_NonNull(entry); + + VoidFn_t finalObjFn = lMap->finalObjFn; + + // first check if key currently exists in map ... + MapCell_t *curCell = findCellByKey(lMap, key); + if (curCell != NULL) { + // an existing cell found under key found ... + if (curCell->content != entry) { + // updates if content is distinct from entry ... + finalObjFn(curCell->content); // recycles current map content + curCell->content = entry; // enters new content + } + } + else { + // Insert fresh cell into linear map + insertNewCell(lMap, key, entry); + } +} + +// Removes existing entry in given linearMap under key +// - returns the object removed (if key exists) +void *removeEntry_LM(LinearMap_t *lMap, unsigned long key) { + req_NonNull(lMap); + + // traversal pointers + MapCell_t *rootCell = lMap->firstCell; + MapCell_t *prevCell = NULL; // parent of curCell + MapCell_t *curCell = rootCell; // child of prevCell + + // object pointer + void *object = NULL; + + // Empty map case + if (rootCell == NULL) return NULL; + + // Remove from non-empty linear map + while (curCell != NULL) { + if (curCell->key == key) { + // key found + if (prevCell == NULL) { + // make next cell = rootCell + rootCell = curCell->nextCell; + } + else { + // make prevCell point at following cell + prevCell->nextCell = curCell->nextCell; + } + // capture object + object = curCell->content; + curCell->content = NULL; + + // recycle curCell + deallocateCell(curCell); + break; + } + else if (curCell-> key > key) { + // key doesn't exist in lMap + return NULL; + } + + // Moving pointers forwards + prevCell = curCell; + curCell = prevCell->nextCell; + } + + // update the root + lMap->firstCell = rootCell; + + // decrement the size + lMap->size += 1; + + // return the object from removed cell. + return object; +} + + +int size_LM(LinearMap_t *lMap) { + if (lMap == NULL) return 0; + + return lMap->size; +} + + +void clear_LM(LinearMap_t *lMap) { + req_NonNull(lMap); + + MapCell_t *curCell = lMap->firstCell; + MapCell_t *nextCell = NULL; + + VoidFn_t finalObjFn = lMap->finalObjFn; + + // traverse down list + while (curCell != NULL) { + // reset the content + finalObjFn(curCell->content); + + // get next cell + nextCell = curCell->nextCell; + + // deallocate current cell + deallocateCell(curCell); + + // Move forwards to next cell + curCell = nextCell; + } +} + + +/******************************************************************************* + Auxilliary cell functions +*******************************************************************************/ + +MapCell_t *findCellByKey(LinearMap_t *lMap, unsigned long key) { + req_NonNull(lMap); + + MapCell_t *curCell = lMap->firstCell; + unsigned long curKey; + + while (curCell != NULL) { + curKey = curCell->key; + if (curKey == key) + return curCell; + + curCell = curCell->nextCell; + } + + return NULL; +} + +void insertNewCell(LinearMap_t *lMap, unsigned long key, void *entry) { + MapCell_t *newCell = allocateCell(); + + // create and populate a new cell + newCell->key = key; + newCell->content = entry; + newCell->nextCell = NULL; + + // traversal pointers + MapCell_t *rootCell = lMap->firstCell; + MapCell_t *prevCell = NULL; // parent of nextCell + MapCell_t *nextCell = rootCell; // child of prevCell + + // Empty map case ... + if (nextCell == NULL) { + // the rootCell is null ... + req_Null(rootCell); + lMap->firstCell = newCell; + return; + } + + // Insert newCell into non-empty linear map + while (nextCell != NULL) { + if (nextCell-> key > key) { + // add new cell + if (prevCell == NULL) { + newCell->nextCell = rootCell; + rootCell = newCell; + } + else { + nextCell->nextCell = nextCell; + prevCell->nextCell = newCell; + } + } + + prevCell = nextCell; + nextCell = prevCell->nextCell; + } + + // make new cell = first cell + lMap->firstCell = rootCell; + + // increment the size + lMap->size += 1; +} + + +/******************************************************************************* + Cell memory management +*******************************************************************************/ + +MemMgr_t *freeCellsList = NULL; + +MapCell_t *allocateCell() { + if (freeCellsList == NULL) { + freeCellsList = new_MM(sizeof(MapCell_t)); + } + + return (MapCell_t *)allocateObject_MM(freeCellsList); +} + +void deallocateCell(MapCell_t *cell) { + deallocateObject_MM(freeCellsList, sizeof(MapCell_t), cell); +} diff --git a/hash_fusion/lib/linearMap.h b/hash_fusion/lib/linearMap.h new file mode 100644 index 0000000000..a3ded0bb7c --- /dev/null +++ b/hash_fusion/lib/linearMap.h @@ -0,0 +1,75 @@ +#ifndef __INDEX_MAP_H__ +#define __INDEX_MAP_H__ + +#include "utils.h" +#include "bytevector.h" +#include "stringbuffer.h" + + +/******************************************************************************* + linearMap.h + + Linear indexed maps + - Encodes a mapping as a linear linked list. + - Keys are encoded as unsigned longs (e.g. can contain void *) + - Key comparison is UNORDERED and is literal equality. + + Author: brian.monahan@hpe.com + + (c) Copyright 2017 Hewlett Packard Enterprise Development LP + + 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. + + 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. +*******************************************************************************/ + +typedef struct linearMap LinearMap_t; + +// prototypes + +// generates new LinearMap_t +LinearMap_t *new_LM(); + +// Deallocate linear map +void deallocate_LM(void *item); + +// Set object finaliser function ... +// - No finalisation happens for data items unless this is set. +void setFinaliser_LM(LinearMap_t *lmap, VoidFn_t finalObjFn); + +// Looks up entry in map using the key +void *getEntry_LM(LinearMap_t *lmap, unsigned long key); + +// Adds/updates entry under key to given linearMap +void addEntry_LM(LinearMap_t *lmap, unsigned long key, void *entry); + +// Removes existing entry in given linearMap under key +// - returns the object removed (if key exists) +void *removeEntry_LM(LinearMap_t *lmap, unsigned long key); + +// Calculate size +int size_LM(LinearMap_t *lmap); + +// Clear existing map +void clear_LM(LinearMap_t *lmap); + +#endif diff --git a/hash_fusion/lib/linkedList.c b/hash_fusion/lib/linkedList.c new file mode 100644 index 0000000000..c51d2e676f --- /dev/null +++ b/hash_fusion/lib/linkedList.c @@ -0,0 +1,829 @@ + +/******************************************************************************* + linkedList.c + + Linked lists ... + - can add elements at either end (i.e. stack/queue semantics) + - efficient append and reverse (linear) + + Author: brian.monahan@hpe.com + + (c) Copyright 2017 Hewlett Packard Enterprise Development LP + + 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. + + 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. +*******************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "alloc.h" +#include "linkedList.h" +#include "fragment.h" + +// Default status to allow updates to list +#define DEFAULT_ALLOW_UPDATES TRUE + +// Top Level of List object +struct linkedList { + Boolean_t allowUpd; // Flag to allow updates or not + int length; // List length + VoidFn_t finalFn; + ListNode_t *first; + ListNode_t *last; +}; + + +// List nodes +struct listNode { + void *data; + ListNode_t *next; +}; + + +// Memory Management +MemMgr_t *linkedList_MemMgr = NULL; +MemMgr_t *listNode_MemMgr = NULL; + +// local methods/prototypes +static void ensureMemMgmt(); +static void deallocateNodes(ListNode_t *nodes, VoidFn_t finalFn); + +static void ensureMemMgmt() { + if (linkedList_MemMgr == NULL) { + linkedList_MemMgr = new_MM(sizeof(LinkList_t)); + } + + if (listNode_MemMgr == NULL) { + listNode_MemMgr = new_MM(sizeof(ListNode_t)); + } +} + +static void deallocateNodes(ListNode_t *nodes, VoidFn_t finalFn) { + if (nodes == NULL) return; + + // Ensure memory management ... + ensureMemMgmt(); + + VoidFn_t deallocFn = (finalFn == NULL ? nullVoidFn : finalFn); + nullVoidFn(nodes); + + ListNode_t *curNode = nodes; + ListNode_t *nextNode = NULL; + + // walk the list to deallocate nodes + while (curNode != NULL) { + nextNode = curNode->next; + + // deallocate object + deallocFn(curNode->data); + + // Nullify node content + NULLIFY_OBJ(curNode, ListNode_t); + + // recycle the node + deallocateObject_MM(listNode_MemMgr, sizeof(ListNode_t), curNode); + + // advance the curNode to the next ... + curNode = nextNode; + } +} + + +/******************************************************************************* + Methods +*******************************************************************************/ + +// creates a newly allocated link list ... +LinkList_t *new_LL() { + + // ensure that the allocation structures exists + ensureMemMgmt(); + + LinkList_t *newList = allocateObject_MM(linkedList_MemMgr); + + newList->allowUpd = DEFAULT_ALLOW_UPDATES; + newList->length = 0; + newList->finalFn = nullVoidFn; + newList->first = NULL; + newList->last = NULL; + + return newList; +} + + +// Allow/disallow updates +Boolean_t getAllowUpdates_LL(LinkList_t *lst) { + req_NonNull(lst); + + return (lst->allowUpd); +} + +void setAllowUpdates_LL(LinkList_t *lst, Boolean_t status) { + req_NonNull(lst); + + lst->allowUpd = status; +} + + +// Deallocates a link list +void deallocate_LL(LinkList_t *lst) { + deallocateWithFinaliser_LL(lst, lst->finalFn); +} + + +// Deallocates a link list - with specific finaliser +void deallocateWithFinaliser_LL(LinkList_t *lst, VoidFn_t finalFn) { + if (lst == NULL) return; + + // ensure that the allocation structures exists + ensureMemMgmt(); + + deallocateNodes(lst->first, finalFn); + + // nullify/scrub attributes + NULLIFY_OBJ(lst, LinkList_t); + + deallocateObject_MM(linkedList_MemMgr, sizeof(LinkList_t), lst);} + + +// Resets a link list +// -the finaliser function (if set) is retained. +void reset_LL(LinkList_t *lst) { + if (lst == NULL) return; + + // deallocate the elements + deallocateNodes(lst->first, lst->finalFn); + + lst->length = 0; + lst->first = NULL; + lst->last = NULL; +} + + +// set finaliser function ... +void setFinaliserFn(LinkList_t *lst, VoidFn_t finalFn) { + req_NonNull(lst); + + lst->finalFn = finalFn; +} + + +// get length of link list +int getLength_LL(LinkList_t *lst) { + req_NonNull(lst); + + return lst->length; +} + + +// calc. length of link list +int calcLength_LL(LinkList_t *lst) { + req_NonNull(lst); + + int count = 0; + ListNode_t *curNode = getTopNode_LL(lst); + + while (curNode != NULL) { + count += 1; + curNode = curNode->next; + } + + return count; +} + +// add object to top of the list (stack-wise - LIFO) +void addObject_LL(LinkList_t *lst, void *obj) { + req_NonNull(lst); + + ListNode_t *newNode = allocateObject_MM(listNode_MemMgr); + + lst->length += 1; + newNode->data = obj; + + if (lst->last == NULL) { + newNode->next = NULL; + lst->first = newNode; + lst->last = newNode; + } + else { + newNode->next = lst->first; + lst->first = newNode; + } +} + + +// synonym for addObject_LL +void pushObject_LL(LinkList_t *lst, void *obj) { + addObject_LL(lst, obj); +} + + +// add object to end of the list (stack-wise - FIFO) +void addEndObject_LL(LinkList_t *lst, void *obj) { + req_NonNull(lst); + + ListNode_t *lastNode = lst->last; + ListNode_t *newNode = allocateObject_MM(listNode_MemMgr); + + lst->length += 1; + newNode->data = obj; + newNode->next = NULL; + + if (lastNode == NULL) { + lst->last = newNode; + lst->first = newNode; + } + else { + // make current last node point at the new node + lastNode->next = newNode; + lst->last = newNode; + } +} + + +// gets the top element (i.e. the front element) - or NULL (if empty). +// - does not modify the list +void *getTopObject_LL(LinkList_t *lst) { + req_NonNull(lst); + + ListNode_t *firstNode = lst->first; + + if (firstNode == NULL) { + return NULL; + } + return firstNode->data; +} + +void *getHead_LL(LinkList_t *lst) { + return getTopObject_LL(lst); +} + +void *popObject_LL(LinkList_t *lst) { + return getTopObject_LL(lst); +} + +// Gets the end data element in list +void *getEndObject_LL(LinkList_t *lst) { + req_NonNull(lst); + + ListNode_t *endNode = lst->last; + + if (endNode == NULL) { + return NULL; + } + return endNode->data; +} + + +// Sets the end data element in list +// - returns the old pointer +void *setEndObject_LL(LinkList_t *lst, void *obj) { + req_NonNull(lst); + + ListNode_t *endNode = lst->last; + + if (endNode == NULL) { + return NULL; + } + + void *result = endNode->data; + + endNode->data = obj; + return result; +} + + +// Gets the Nth element (0 based) +// - Negative index counts back from the end +// - If index is out of range, return NULL +void *getNthObject_LL(LinkList_t *lst, int index) { + req_NonNull(lst); + + if (index < 0) { + index = (lst->length)+index; + } + + if (index < 0) { + return NULL; + } + + if (lst->length <= index) return NULL; + + ListNode_t *curNode = lst->first; + + for (int count = index; curNode != NULL; count--) { + if (count == 0) { + return curNode->data; + } + curNode = curNode->next; + } + + return NULL; +} + + +// Update Nth object in the list +// - If the allowUpd property is FALSE, then make no change and return NULL. +// - Returns the old pointer ... +// - Negative index counts back from the end +// - If index is out of range, return NULL +void *updateNthObject_LL(LinkList_t *lst, int index, void *newObj) { + req_NonNull(lst); + + if (!lst->allowUpd) return NULL; + + void *oldObj = NULL; + + // check for negative index - meaning index from end of list + if (index < 0) { + + // covert to positive index + index = (lst->length)+index; + + // retest index following update + if (index < 0) { + // index is still out of range + return NULL; + } + } + + + if (lst->length <= index) return NULL; + + ListNode_t *curNode = lst->first; + + for (int count = index; curNode != NULL; count--) { + if (count == 0) { + oldObj = curNode->data; + curNode->data = newObj; + return oldObj; + } + + curNode = curNode->next; + } + + return NULL; +} + +// Insert object at Nth position in the list (0 based) +// - Negative index counts back from the end +// - If index is out of range, return with no update +Boolean_t insertNthObject_LL(LinkList_t *lst, int index, void *obj) { + req_NonNull(lst); + + //Boolean_t result = FALSE; + + //void *oldObj = NULL; + + // check for negative index - meaning index from end of list + if (index < 0) { + + // covert to positive index + index = (lst->length)+index; + + // retest index following update + if (index < 0) { + // index is still out of range + return FALSE; + } + } + + if (lst->length <= index) return FALSE; + + ListNode_t *prevNode = NULL; + ListNode_t *curNode = lst->first; + + for (int count = index; count >= 0; count--) { + if (count == 0) { + ListNode_t *newNode = allocateObject_MM(listNode_MemMgr); + + // update the length + lst->length += 1; + + // update the new node + newNode->data = obj; + newNode->next = curNode; + + // position the new node + if (prevNode == NULL) { + // make new node the top node + lst->first = newNode; + } + else { + // make new node follow on from prevNode ... + prevNode->next = newNode; + } + + return TRUE; + } + + prevNode = curNode; + curNode = curNode->next; + } + + return FALSE; +} + + +// Clone source list into dest list. +void cloneList_LL(LinkList_t *dest, LinkList_t *source) { + req_NonNull(dest); + req_NonNull(source); + + // deallocate any current destination nodes + deallocateNodes(dest->first, dest->finalFn); + + // reset the destination linked list object + dest->length = source->length; + dest->first = NULL; + dest->last = NULL; + + ListNode_t *curNode = source->first; + + ListNode_t *prevNewNode = NULL; + ListNode_t *curNewNode = NULL; + + while (curNode != NULL) { + curNewNode = allocateObject_MM(listNode_MemMgr); + + curNewNode->data = curNode->data; + + + if (dest->first == NULL) { + dest->first = curNewNode; + } + + if (prevNewNode != NULL) { + prevNewNode->next = curNewNode; + } + + prevNewNode = curNewNode; + + curNode = curNode->next; + } + + // Make dest->last points at the last node of the new list. + dest->last = prevNewNode; +} + +// Append source list to end of dest list. +// - destructively modifies the dest list by adding cloned +// source list. +void nAppendList_LL(LinkList_t *dest, LinkList_t *source) { + req_NonNull(dest); + req_NonNull(source); + + // update the length + dest->length += source->length; + + // the curNode pointer starts at first node of source. + ListNode_t *curNode = source->first; + + ListNode_t *prevNewNode = dest->last; // set to existing last elem. + ListNode_t *curNewNode = NULL; + + while (curNode != NULL) { + // allocate node + curNewNode = allocateObject_MM(listNode_MemMgr); + + // copy over the data pointer ... + // - data is shared + curNewNode->data = curNode->data; + + // attach current node to previous new node + if (prevNewNode != NULL) { + prevNewNode->next = curNewNode; + } + + // update the first cell of dest if necessary + if (dest->first == NULL) { + dest->first = curNewNode; + } + + // track the previous node + prevNewNode = curNewNode; + + // advance current Node + curNode = curNode->next; + } + + // dest->last now points at the last node of the new list. + dest->last = prevNewNode; +} + +// reverse-append source list to end of dest list. +// - source list is not modified. +// - dest list is destructively updated with the reverse of source. +// - length of dest is increased by length of source list +void nRevAppendList_LL(LinkList_t *dest, LinkList_t *source) { + req_NonNull(dest); + req_NonNull(source); + + // return with + if (source->length == 0) return ; + + // update the length + dest->length += source->length; + + ListNode_t *lastNode = dest->last; // pointer to last node of destination ... + ListNode_t *curNode = source->first; // currrent pointer into source list + + ListNode_t *accumEndNode = NULL; // place to accumulate the new end list + ListNode_t *curTopNode = NULL; + ListNode_t *curNewNode = NULL; + + ListNode_t *newLastNode = NULL; // records the first node added to end list + + while (curNode != NULL) { + // allocate node + curNewNode = allocateObject_MM(listNode_MemMgr); + + // keep track of the current top node for new end list + accumEndNode = curNewNode; + + // record the first new node allocated + // - this will be the new last node of the dest list + if (newLastNode == NULL) { + newLastNode = accumEndNode; + } + + // update the current new node ... + // - data is shared + // - curNewData + curNewNode->data = curNode->data; + curNewNode->next = curTopNode; + + // + curTopNode = curNewNode; + + // advance current Node to next + curNode = curNode->next; + } + + if (dest->first == NULL) { + dest->first = accumEndNode; + } + + if (lastNode != NULL) { + lastNode->next = accumEndNode; + } + + // dest->last now points at the last node of the new list. + if (newLastNode != NULL) { + dest->last = newLastNode; + } +} + +// Destructively reverse given list +// - reuses existing cells - no allocation needed ... +void nReverseList_LL(LinkList_t *lst) { + req_NonNull(lst); + + // return for null list + if (lst->length == 0) return; + + // non-null list + ListNode_t *oldFirstNode = lst->first; + ListNode_t *oldLastNode = lst->last; + + ListNode_t *curNode = oldFirstNode; // currrent pointer into source list + ListNode_t *nextNode = NULL; + + ListNode_t *accumEndNode = NULL; // place to accumulate the new reversed list + + while (curNode != NULL) { + nextNode = curNode->next; + curNode->next = accumEndNode; + + // keep track of the current top node for new end list + accumEndNode = curNode; + + // advance current node to next + curNode = nextNode; + } + + lst->first = oldLastNode; + lst->last = oldFirstNode; +} + + +/******************************************************************************* + List Nodes Methods + - Methods for walking/manipulating list nodes directly +*******************************************************************************/ +// Gets the top node +ListNode_t *getTopNode_LL(LinkList_t *lst) { + req_NonNull(lst); + + return lst->first; +} + + +// Sets the top node (UNSAFE) +// - returns the old top node (in case it needs to be deallocated) +ListNode_t *setTopNode_LL(LinkList_t *lst, ListNode_t *topNode) { + req_NonNull(lst); + + ListNode_t *oldTopNode = lst->first; + lst->first = topNode; + + // returns the old top node + return oldTopNode; +} + + +// Deallocate a list node +// - returns the next node +// - the value object can be deallocated via the custom deallocObjFn. +// - if deallocObjFn is NULL, then no deallocation is performed ... +ListNode_t *deallocateNode_LL(ListNode_t *node, VoidFn_t deallocObjFn) { + if (node == NULL) return NULL; + + ListNode_t *oldNextNode = node->next; + + VoidFn_t finalObjFn = (deallocObjFn == NULL ? nullVoidFn : deallocObjFn); + + // deallocate object + finalObjFn(node->data); + + // Nullify node content + node->data = NULL; + node->next = NULL; + + // recycle the node + deallocateObject_MM(listNode_MemMgr, sizeof(ListNode_t), node); + + return oldNextNode; +} + +// Gets the Nth node (0-based) +// - Negative index counts back from the end +// - If index is out of range, return NULL +ListNode_t *getNthNode_LL(LinkList_t *lst, int index) { + req_NonNull(lst); + + if (index < 0) { + index = (lst->length)+index; + } + + if (index < 0) { + return NULL; + } + + if (lst->length <= index) return NULL; + + ListNode_t *curNode = lst->first; + + for (int count = index; curNode != NULL; count--) { + if (count == 0) { + return curNode; + } + curNode = curNode->next; + } + + return NULL; +} + + +// Allocates a fresh list node +ListNode_t *newNodeObject_LL(void *obj, ListNode_t *nextNode) { + ListNode_t *newNode = allocateObject_MM(listNode_MemMgr); + + newNode->data = obj; + newNode->next = nextNode; + + return newNode; +} + + +// Gets the object from the given node - or NULL (if empty). +void *getNodeObject_LL(ListNode_t *node) { + if (node == NULL) return NULL; + + return node->data; +} + + +// Sets the object from the given node. +// - returns the old pointer +void *setNodeObject_LL(ListNode_t *node, void *newObj) { + if (node == NULL) return NULL; + + void *result = node->data; + + node->data = newObj; + + return result; +} + + +// Gets the next node (could be NULL) following the given node ... +ListNode_t *getNextNode_LL(ListNode_t *node) { + if (node == NULL) return NULL; + + return node->next; +} + + +// Sets the next node (could be NULL) following the given node ... (UNSAFE) +// - returns the old node (which may need to be disposed of). +// - fails if curNode is NULL. +// - This could break the representation as: +// - the length is not updated +// - the last element pointer is not maintained. +// - Update the list after mainipulation. +ListNode_t *setNextNode_LL(ListNode_t *curNode, ListNode_t *newNextNode) { + req_NonNull(curNode); + + ListNode_t *oldNextNode = curNode->next; + curNode->next = newNextNode; + + return oldNextNode; +} + + +/******************************************************************************* + List representation maintenance ... + + - USE WITH CARE ... + - in general, these are either UNSAFE (not guaranteed) OR EXPENSIVE. + +*******************************************************************************/ +// Set length of link list (UNSAFE) +// - Can break the representation +void setLength_LL(LinkList_t *lst, int length) { + req_NonNull(lst); + + lst->length = length; +} + +// Increment length of link list (UNSAFE) +// - Can break the representation +void incrLength_LL(LinkList_t *lst, int increment) { + req_NonNull(lst); + + lst->length += increment; +} + +// Set end of list (UNSAFE) +// - Checks that next node pointer of newEndNode is NULL (fails if not). +// - Can break the representation +void setEndNode_LL(LinkList_t *lst, ListNode_t *newEndNode) { + req_NonNull(lst); + + if (newEndNode != NULL && newEndNode->next != NULL) { + diagnostic("setEndNode_LL : End node should have NULL successor ..."); + error_exit(); + } + + lst->last = newEndNode; +} + +// Update link list (EXPENSIVE - this traverses list from fromNode) +// - starts from top object +// - ensures the current length is valid +// - ensures that the pointer to end node is valid +// - returns the current length +int updateList_LL(LinkList_t *lst) { + req_NonNull(lst); + + // pointer to previous node ... + ListNode_t *prevNode = NULL; + + // walk the list ... + int count = 0; + for (ListNode_t *curNode = lst->first; curNode != NULL; count++) { + prevNode = curNode; + curNode = curNode->next; + } + + // update the length ... + lst->length = count; + + // update the pointer to the end node ... + lst->last = prevNode; + + return count; +} diff --git a/hash_fusion/lib/linkedList.h b/hash_fusion/lib/linkedList.h new file mode 100644 index 0000000000..510a99b662 --- /dev/null +++ b/hash_fusion/lib/linkedList.h @@ -0,0 +1,205 @@ +#ifndef __LINKED_LIST_H__ +#define __LINKED_LIST_H__ + +/******************************************************************************* + linkedList.h + + Linked lists ... + - can add elements at either end (i.e. stack/queue semantics supported) + - efficient append and reverse (linear) + + Author: brian.monahan@hpe.com + + (c) Copyright 2017 Hewlett Packard Enterprise Development LP + + 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. + + 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. +*******************************************************************************/ + +#include "utils.h" + +// Linked List structure +typedef struct linkedList LinkList_t; + +// List Node structure +typedef struct listNode ListNode_t; + + +/******************************************************************************* + Methods on Lists +*******************************************************************************/ + +// Creates a newly allocated link list ... +LinkList_t *new_LL(); + +// Set finaliser function ... +void setFinaliserFn(LinkList_t *lst, VoidFn_t finalFn); + +// Allow/disallow updates +// - This only inhibits updates using updateNthObject +// - Updates etc. using the ListNode based operations still permitted. +Boolean_t getAllowUpdates_LL(LinkList_t *lst); +void setAllowUpdates_LL(LinkList_t *lst, Boolean_t status); + +// Deallocates a link list +void deallocate_LL(LinkList_t *lst); + +// Deallocates a link list - with finaliser +void deallocateWithFinaliser_LL(LinkList_t *lst, VoidFn_t finalFn); + +// Resets a link list +// -the finaliser function (if set) is retained. +void reset_LL(LinkList_t *lst); + +// get length of link list +int getLength_LL(LinkList_t *lst); + +// calc. length of link list +int calcLength_LL(LinkList_t *lst); + +// add object to top of the list (stack-wise - LIFO) +void addObject_LL(LinkList_t *lst, void *obj); +void pushObject_LL(LinkList_t *lst, void *obj); + +// add object to end of the list (stack-wise - FIFO) +void addEndObject_LL(LinkList_t *lst, void *obj); + +// gets the top element (i.e. the front element) - or NULL (if empty). +// - does not modify the list +void *getTopObject_LL(LinkList_t *lst); +void *getHead_LL(LinkList_t *lst); + +// return top element, but also removes it from list. +void *popObject_LL(LinkList_t *lst); + +// Gets the end data element in list +void *getEndObject_LL(LinkList_t *lst); + +// Sets the end data element in list +// - returns the old pointer +void *setEndObject_LL(LinkList_t *lst, void *obj); + +// Gets the Nth element (0 based) +// - Negative index counts back from the end +// - If index is out of range, return NULL +void *getNthObject_LL(LinkList_t *lst, int index); + +// Update Nth object in the list +// - Returns the old pointer ... +// - Negative index counts back from the end +// - If index is out of range, return NULL +void *updateNthObject_LL(LinkList_t *lst, int index, void *obj); + +// Insert object at Nth position in the list +// - Negative index counts back from the end +// - If index is out of range, return FALSE +// - returns TRUE, if insert completed. +Boolean_t insertNthObject_LL(LinkList_t *lst, int index, void *obj); + +// Clone source list into dest list. +void cloneList_LL(LinkList_t *dest, LinkList_t *source); + +// Append source list to end of dest list. +// - destructively modifies the dest list by adding cloned +// source list. +void nAppendList_LL(LinkList_t *dest, LinkList_t *source); + +// reverse-append source list to end of dest list. +void nRevAppendList_LL(LinkList_t *dest, LinkList_t *source); + +// Destructively reverse given list +// - reuses existing cells - no allocation needed ... +void nReverseList_LL(LinkList_t *lst); + + +/******************************************************************************* + List Node Methods + - Methods for walking/manipulating list nodes directly +*******************************************************************************/ +// Gets the top node (i.e. element 0) +ListNode_t *getTopNode_LL(LinkList_t *lst); + +// Sets the top node +// - returns the old top node (in case it needs to be deallocated) +// - updates internals to use the new list defined by topNode. +ListNode_t *setTopNode_LL(LinkList_t *lst, ListNode_t *topNode); + +// Deallocate a list node +// - returns the next node +// - the value object can be deallocated via the custom deallocObjFn. +// - if deallocObjFn is NULL, then no deallocation is performed ... +ListNode_t *deallocateNode_LL(ListNode_t *node, VoidFn_t deallocObjFn); + +// Gets the Nth node (0-based) +// - Negative index counts back from the end +// - If index is out of range, return NULL +ListNode_t *getNthNode_LL(LinkList_t *lst, int index); + +// Allocates a fresh list node +ListNode_t *newNodeObject_LL(void *obj, ListNode_t *nextNode); + +// Gets the object from the given node - or NULL (if empty). +void *getNodeObject_LL(ListNode_t *node); + +// Sets the object from the given node - or NULL (if empty). +// - returns the old pointer +void *setNodeObject_LL(ListNode_t *node, void *newObj); + +// Gets the next node (could be NULL) following the given node ... +ListNode_t *getNextNode_LL(ListNode_t *node); + +// Sets the next node (could be NULL) following the given node ... +// - returns the old node (which may need to be disposed of). +// - fails if curNode is NULL. +ListNode_t *setNextNode_LL(ListNode_t *curNode, ListNode_t *newNextNode); + + +/******************************************************************************* + List representation maintenance ... + + - USE WITH CARE ... + - in general, these are either UNSAFE (not guaranteed) OR EXPENSIVE. + +*******************************************************************************/ +// Set length of link list (UNSAFE) +// - Can break the representation +void setLength_LL(LinkList_t *lst, int length); + +// Increment length of link list (UNSAFE) +// - Can break the representation +void incrLength_LL(LinkList_t *lst, int increment); + +// Set end of list (UNSAFE) +// - Checks that next node pointer of newEndNode is NULL (fails if not). +// - Can break the representation +void setEndNode_LL(LinkList_t *lst, ListNode_t *newEndNode); + +// Update link list (EXPENSIVE - this traverses list from fromNode) +// - starts from top object +// - ensures the current length is valid +// - ensures that the last pointer is valid +// - returns the current length +int updateList_LL(LinkList_t *lst); + + +#endif diff --git a/hash_fusion/lib/matrix.c b/hash_fusion/lib/matrix.c new file mode 100644 index 0000000000..9ac77e093f --- /dev/null +++ b/hash_fusion/lib/matrix.c @@ -0,0 +1,1689 @@ +/* matrix.c + + Basic matrix operations ... + + Author: brian.monahan@hpe.com + + (c) Copyright 2017 Hewlett Packard Enterprise Development LP + + 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. + + 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. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "utils.h" +#include "bytevector.h" +#include "stringbuffer.h" +#include "matrix.h" +#include "random.h" +#include "linearMap.h" +#include "alloc.h" + +/******************************************************************************* + Matrix structure + + - All matrices are stored square with integer entries (for simplicity of indexing). + + - Byte_t entries with arithmetic modulo 256. + + - Stored as a flat linear array in row major order (i.e. default for C/C++). + + - The size of the array is one more than the number of elements + (i.e. compatibility with bytevectors). + + - Linear positions in matrix: [col, row] is: dim*row + col. +*******************************************************************************/ + +struct matrix { + int dimension; // Dimension of (square) matrix + int base; // Base of matrix operations + int capacity; // Size of array (length of underlying array) = dim^2 + 1 + Boolean_t isTriangular; // Indicates if matrix is upper triangular. + Byte_t *array; // flat linear memory storage (of size: capacity). +}; + + +// This sets the top limit for period finding ... +#define MAX_PERIOD_LIMIT 20000 + + +/******************************************************************************* + Static method prototypes +*******************************************************************************/ +static void ensureMemMgmt(); + +static void calcOffsetArray(int dim); + +static inline void fullMultiply(Matrix_t *result, Matrix_t *ma, Matrix_t *mb); + +//static inline void auxTriMultiply_STANDARD(Matrix_t *result, Matrix_t *ma, Matrix_t *mb); +//static inline void auxTriMultiply_FAST(Matrix_t *result, Matrix_t *ma, Matrix_t *mb); +//static inline void auxTriMultiply_FAST2(Matrix_t *result, Matrix_t *ma, Matrix_t *mb); +//static inline void auxTriMultiply_FASTER(Matrix_t *result, Matrix_t *ma, Matrix_t *mb); +static inline void auxTriMultiply_FASTER2(Matrix_t *result, Matrix_t *ma, Matrix_t *mb); +//static inline void auxTriMultiply_FASTER3(Matrix_t *result, Matrix_t *ma, Matrix_t *mb); +//static inline void auxTriMultiply_FASTER4(Matrix_t *result, Matrix_t *ma, Matrix_t *mb); +//static inline void auxTriMultiply_FASTER5(Matrix_t *result, Matrix_t *ma, Matrix_t *mb); + +static Byte_t dotProduct(Byte_t *aArray, Byte_t *bArray, int dim, int row, int col); +//static Byte_t dotProduct_Tri(Byte_t *aArray, Byte_t *bArray, int dim, int posn, int row, int col); +static Byte_t dotProduct_Tri2(Byte_t *aArray, Byte_t *bArray, int dim, int rowStart, int posn, int row, int col); +//static Byte_t dotProduct_Tri3(Byte_t *aArray, Byte_t *bArray, int dim, int rowStart, int posn, int row, int col); +//static Byte_t dotProduct_Tri4(Byte_t *aArray, Byte_t *bArray, int dim, int rowStart, int posn, int row, int col); +//static Byte_t dotProduct_Tri5(Byte_t *aArray, Byte_t *bArray, int dim, int rowStart, int posn, int row, int col); + +static void initPowerOfMemoMap(Matrix_t *ma); +static void auxTriPowerOf(Matrix_t *result, Matrix_t *ma, int power); +static void auxPowerOf(Matrix_t *result, Matrix_t *ma, int power); +static void auxTriPowerOf(Matrix_t *result, Matrix_t *ma, int power); +static void auxPowerOf(Matrix_t *result, Matrix_t *ma, int power); + +static int auxTriPeriodOfMatrix(Matrix_t *ma); +static int auxPeriodOfMatrix(Matrix_t *ma); +static void initInverseCalc(Matrix_t *ma); +static int auxTriPeriodOfMatrix(Matrix_t *ma); +static int auxPeriodOfMatrix(Matrix_t *ma); + +static void disposeMatrix(void *obj); + +static void auxStartOfRow(StringBuf_t *sBuf, int row, char *indent); +static void auxShowMatrix(const char *fmt, Matrix_t *ma, StringBuf_t *sBuf, char *indent); +static void auxShowMatrix(const char *fmt, Matrix_t *ma, StringBuf_t *sBuf, char *indent); +static void auxStartOfRow(StringBuf_t *sBuf, int row, char *indent); + +char *debugMatrix(Matrix_t *ma); +char *xdebugMatrix(Matrix_t *ma); + +char *dump_Matrix(Matrix_t *ma, char *offset); + +static int currentDim = 0; + +/******************************************************************************* + Memory management +*******************************************************************************/ +static MemMgr_t *matrix_MemMgr = NULL; + +static void ensureMemMgmt() { + if (matrix_MemMgr == NULL) { + matrix_MemMgr = new_MM(sizeof(Matrix_t)); + setFinaliser_MM(matrix_MemMgr, disposeMatrix); + + // Setting up byte multiply table + //setupByteMultiply(); + } +} + + +// Allocates matrix of given dimension and triangularity +// - can specify dimension of matrix. +// - can specify triangular. +// - if triangular, sets matrix as identity +// - otherwise, zeroes the matrix +Matrix_t *allocateMatrix(int dim, Boolean_t isTriangular) { + if (dim == 0) { + dim = currentDim; + } + + req_Pos(dim); + + // update the current dimension + currentDim = dim; + + ensureMemMgmt(); + + Matrix_t *result = allocateObject_MM(matrix_MemMgr); + + resetMatrix(result, dim, isTriangular); + + return result; +} + +Matrix_t *allocateTriMatrix(int dim) { + return allocateMatrix(dim, TRUE); +} + + +// resets the given matrix appropriately +// - can specify dimension of matrix. +// - can specify triangular. +// - if triangular, sets matrix as identity +// - otherwise, zeroes the matrix +void resetMatrix(Matrix_t *ma, int dim, Boolean_t isTriangular) { + req_NonNull(ma); + req_Pos(dim); + + ensureMemMgmt(); + + // sets triangular property + ma->isTriangular = isTriangular; + + // new dimension ... needs to change array allocation ... + if (dim != ma->dimension) { + + // set dimension & capacity + ma->dimension = dim; + ma->capacity = (dim*dim)+1; + + // free any existing memory + free(ma->array); + + // allocate fresh memory for the array + ma->array = (Byte_t *)ALLOC_BLK(ma->capacity); + } + + // initialise content + if (ma->isTriangular) { + setIdentityMatrix(ma); + } + else { + setZeroMatrix(ma); + } +} + + +// Releases given matrix and its memory +// - This explicitly does NOT release array storage .... +void deallocateMatrix(void *obj) { + if (obj == NULL) return; + + ensureMemMgmt(); + + Matrix_t *ma = (Matrix_t *)obj; + + deallocateObject_MM(matrix_MemMgr, sizeof(Matrix_t), ma); +} + + +// get/set current dimension +int getCurrentDim() { + return currentDim; +} + +void setCurrentDim(int dim) { + currentDim = dim; +} + + +// Resets a given matrix as an zero matrix +// - unsets the triangular property +void setZeroMatrix(Matrix_t *ma) { + req_NonNull(ma); + + //int dim = ma->dimension; + int capacity = ma->capacity; + Byte_t *array = ma->array; + + // unset triangular property + ma->isTriangular = FALSE; + + // Zero the array + NULLIFY(array, capacity); +} + + +// Resets a given matrix as an identity matrix +// - sets triangular property +void setIdentityMatrix(Matrix_t *ma) { + req_NonNull(ma); + + int dim = ma->dimension; + int capacity = ma->capacity; + Byte_t *array = ma->array; + + // sets triangular property + ma->isTriangular = TRUE; + + // first, zero the array + NULLIFY(array, capacity); + + // Now set leading diagonal to one's. + int posn = 0; + for (int i = 0; i < dim; i++) { + array[posn] = 1; + posn += dim+1; + } +} + + +/******************************************************************************* + Getters and Setters +*******************************************************************************/ + +// Get value ... (column, row) +// - checks array bounds +Byte_t getValue(Matrix_t *ma, int col, int row) { + int dim = ma->dimension; + int capacity = ma->capacity; + + // calculate linear matrix position + int posn = dim*row + col; + + if (0 <= posn && posn < capacity) { + return ma->array[posn]; + } + + diagnostic("matrix.getValue: index out of range - col=%i, row=%i", col, row); + codeError_exit(); +} + +// Set value ... +// - checks array bounds .. (column, row) +void setValue(Matrix_t *ma, int col, int row, Byte_t newVal) { + req_NonNull(ma); + + int dim = ma->dimension; + int capacity = ma->capacity; + + // calculate linear matrix position + int posn = dim*row + col; + + if (0 <= posn && posn < capacity) { + ma->array[posn] = newVal; + return; + } + + diagnostic("matrix.setValue: index out of range - col=%i, row=%i", col, row); + codeError_exit(); +} + +// Gets the dimension of the given matrix ... +int getDimension(Matrix_t *ma) { + req_NonNull(ma); + + return ma->dimension; +} + + +// Returns if matrix is (upper) triangular +Boolean_t isTriangular(Matrix_t *ma) { + req_NonNull(ma); + + return ma->isTriangular; +} + +// Checks if matrix is (upper) triangular +// - updates the isTriangular flag and returns the status. +Boolean_t checkTriangular(Matrix_t *ma) { + req_NonNull(ma); + + int dim = ma->dimension; // dimension of matrix + + Byte_t *array = ma->array; // the content array + + int rowStart = 0; // row start in the array + int posn = 0; // position in the array + + Byte_t curVal = 0; // current value of element + + // Scans the matrix horizontally by column and then vertically by row + for (int col = 0; col < dim; col++) { + rowStart = (col == 0 ? 0 : rowStart + dim); // Calculates position for start of the row. + posn = rowStart + col; // Corresponds to the leading diagonal. + + for (int row = col; row < dim; row++) { + curVal = array[posn]; // This extracts the current value at current position ... + + if (col < row && curVal != 0) { + ma->isTriangular = FALSE; + return FALSE; + } + else if (row == col && curVal != 1) { + ma->isTriangular = FALSE; + return FALSE; + } + + posn += dim; // advances the position by one row in the same column ... + } + } + + ma->isTriangular = TRUE; + return TRUE; +} + + +/******************************************************************************* + Bytevector content extraction and copying ... +*******************************************************************************/ +// Returns the max number of elements available in matrix +// - For upper triangular, this does not include the diagonal or the lower +// triangular elements. +int maxElemsMatrix(Matrix_t *mat) { + req_NonNull(mat); + + int dim = mat->dimension; + int size = mat->capacity; + Boolean_t isTri = mat->isTriangular; + + return (isTri ? triNumber(dim) : size-1); +} + +// triangular number i.e. number of elems above leading diagonal of matrix of size dim. +int triNumber(int dim) { + req_LE(1, dim); + + return dim*(dim - 1)/2; +} + + +// Calculates the size of the smallest upper triangular matrix to contain content +// of given length. +int calcDimension(int length) { + int dim = 2; + int elems = triNumber(dim); + + while (elems < length) { + dim += 1; + elems = triNumber(dim); + } + + return dim; +} + +// Calculates the size of the zero padding for a vector of given length. +int calcPadding(int length) { + int dim = calcDimension(length); + return triNumber(dim) - length; +} + +// Extracts content from given matrix and copies it into the given bytevector. +// - if the bytevector's data vector is NULL, then fresh memory is allocated to fit. +// - if the matrix is triangular, the upper triangular portion of the matrix is captured. +void extractContent(ByteVec_t *dest, Matrix_t *source) { + req_NonNull(source); + req_NonNull(dest); + + int dim = source->dimension; + Boolean_t isTri = source->isTriangular; + + int numEntries = maxElemsMatrix(source); + + // ensures byte vector has the capacity to contain content + ensureCapacity_BV(dest, numEntries+1); + + Byte_t *array = source->array; + + int dataLen = numEntries; + Byte_t *dataVec = getContent_BV(dest); + + if (isTri) { + + // Extract upper triangular elements ... + int vecPosn = 0; // data vector position + int matPosn = 0; // linear matrix position (col, row) is: (dim*row + col) + + // extract the upper triangular elements + // - proceeds by reading each column vertically row-by-row + for (int col = 0; col < dim; col++) { + matPosn = col; + for (int row = 0; row < col; row++) { + if (vecPosn < dataLen) { + dataVec[vecPosn] = array[matPosn]; + } + + vecPosn += 1; // advances to the next element in the vector + matPosn += dim; // advances position to next row in the column + } + } + + } + else { +/* // Extracts square array (i.e. row by row) + int vecPosn = 0; // data vector position + int matPosn = 0; // linear matrix position (col, row) is: (dim*row + col) + + // Proceeds by reading each row and then each column ... + for (int row = 0; row < dim; row++) { + for (int col = 0; col < dim; col++) { + if (vecPosn < dataLen) { + dataVec[vecPosn] = array[matPosn]; + } + + vecPosn += 1; // advances to the next element in the vector + matPosn += 1; // advances position to next row in the column + } + } +*/ + memcpy(dataVec, array, dataLen); + } + + // Ensure that the length of the data reflects the updates made. + setLength_BV(dest, dataLen); +} + + +// Copies the bytevector content into given matrix +// - mapping takes into account if matrix is triangular +void insertContent(Matrix_t *dest, ByteVec_t *content) { + req_NonNull(dest); + req_NonNull(content); + + int dim = dest->dimension; + Boolean_t isTri = dest->isTriangular; + Byte_t *array = dest->array; + + int dataLen = getLength_BV(content); + Byte_t *dataVec = getContent_BV(content); + + if (isTri) { + // Fill upper triangular matrix ... + + int vecPosn = 0; // data vector position + int matPosn = 0; // linear matrix position (col, row) is: (dim*row + col) + + // update the upper triangular elements, setting any remaining entries to zero. + // - proceeds by filling each column (this is for column-based padding) + for (int col = 0; col < dim; col++) { + matPosn = col; + for (int row = 0; row < col; row++) { + array[matPosn] = (vecPosn < dataLen ? dataVec[vecPosn] : 0); + + vecPosn += 1; // advances to the next element in the vector ... + matPosn += dim; // advances position to next row in the column + } + } + } + else { + // Fill square array (i.e. row by row) + + int vecPosn = 0; // data vector position + int matPosn = 0; // linear matrix position (col, row) is: (dim*row + col) + + // update the upper triangular elements, setting any remaining entries to zero. + // - proceeds by filling each row and then each column ... + for (int row = 0; row < dim; row++) { + for (int col = 0; col < dim; col++) { + array[matPosn] = (vecPosn < dataLen ? dataVec[vecPosn] : 0); + + vecPosn += 1; // advances to the next element in the vector ... + matPosn += 1; // advances position to next row in the column + } + } + } +} + +// Swops two matrices of same dimension pointed at by ma and mb +void swopMatrices(Matrix_t *ma, Matrix_t *mb) { + req_NonNull(ma); + req_NonNull(mb); + + if (ma == mb) + return; // Nothing to do + + if (ma->dimension != mb->dimension) { + diagnostic("swopMatrices: argument matrices have different dimensions."); + error_exit(); + } + + // Now swop content .... + Matrix_t tempM = *ma; + *ma = *mb; + *mb = tempM; +} + +// Copies the content of the source matrix into the destination matrix. +// - This destroys the content of the destination matrix ... +void cloneMatrix(Matrix_t *dest, Matrix_t *source) { + req_NonNull(source); + req_NonNull(dest); + + if (source->dimension != dest->dimension) { + diagnostic("cloneMatrix: source and destination matrices have different dimensions."); + error_exit(); + } + + // ensure the destination has same attributes + dest->isTriangular = source->isTriangular; + + // directly copy the source data into the destination array + memcpy(dest->array, source->array, source->capacity); +} + + +/******************************************************************************* + Basic Predicates +*******************************************************************************/ + +// Checks equality of matrices +Boolean_t equalMatrix(Matrix_t *ma, Matrix_t *mb) { + req_NonNull(ma); + req_NonNull(mb); + + // check some basic attributes + if (ma->dimension != mb->dimension) return FALSE; + if (ma->isTriangular != mb->isTriangular) return FALSE; + + // Standard case + int dim = ma->dimension; + Boolean_t isTri = ma->isTriangular; + + Byte_t *aArray = ma->array; + Byte_t *bArray = mb->array; + + int posn = 0; + + if (isTri) { + // Upper triangular matrices ... + for (int col = 0; col < dim; col++) { + posn = col; + for (int row = 0; row < col; row++) { + if (aArray[posn] != bArray[posn]) return FALSE; + + posn += dim; + } + } + } + else { + // Square matrices ... + for (int row = 0; row < dim; row++) { + for (int col = 0; col < dim; col++) { + if (aArray[posn] != bArray[posn]) return FALSE; + + posn += 1; + } + } + } + + // Failed to find difference - therefore equality. + return TRUE; +} + + +// Checks if matrix is the identity +Boolean_t isIdentityMatrix(Matrix_t *ma) { + req_NonNull(ma); + + // Standard case + int dim = ma->dimension; + Boolean_t isTri = ma->isTriangular; + + Byte_t *aArray = ma->array; + + int posn = 0; + + if (isTri) { + // Upper triangular matrices ... + for (int col = 0; col < dim; col++) { + posn = col; + for (int row = 0; row < col; row++) { + if (aArray[posn] != 0) + return FALSE; + + posn += dim; + } + } + } + else { + // Square matrices ... + for (int row = 0; row < dim; row++) { + for (int col = 0; col < dim; col++) { + if (row == col && aArray[posn] != 1) { + return FALSE; + } + else { + if (aArray[posn] != 0) + return FALSE; + } + posn += 1; + } + } + } + + // Failed to find difference - therefore equality. + return TRUE; +} + + +// Checks if matrix is zero +Boolean_t isZeroMatrix(Matrix_t *ma) { + req_NonNull(ma); + + // every upper triangular matrix is non-zero! + if (ma->isTriangular) return FALSE; + + // Square matrices ... + int size = ma->capacity; + Byte_t *aArray = ma->array; + + for (int posn = 0; posn < size-1; posn++) { + if (aArray[posn] != 0) return FALSE; + } + + // Failed to find difference - therefore zero matrix. + return TRUE; +} + + +/******************************************************************************* + Randomised matrix +*******************************************************************************/ +void randomMatrix(Matrix_t *dest) { + req_NonNull(dest); + + int dim = dest->dimension; + Byte_t *array = dest->array; + + if (dest->isTriangular) { + // Fill upper triangular matrix ... + + int vecPosn = 0; // data vector position + int matPosn = 0; // linear matrix position (col, row) is: (dim*row + col) + + // update the upper triangular elements, setting any remaining entries to zero. + // - proceeds by filling each column (this is for column-based padding) + for (int col = 0; col < dim; col++) { + matPosn = col; + for (int row = 0; row < col; row++) { + array[matPosn] = nextRandom_BYTE(); + + vecPosn += 1; // advances to the next element in the vector ... + matPosn += dim; // advances position to next row in the column + } + } + + } + else { + // Fill square array (i.e. row by row) + + int vecPosn = 0; // data vector position + int matPosn = 0; // linear matrix position (col, row) is: (dim*row + col) + + // update the upper triangular elements, setting any remaining entries to zero. + // - proceeds by filling each row and then each column ... + for (int row = 0; row < dim; row++) { + for (int col = 0; col < dim; col++) { + array[matPosn] = nextRandom_BYTE(); + + vecPosn += 1; // advances to the next element in the vector ... + matPosn += 1; // advances position to next row in the column + } + } + } +} + + +/******************************************************************************* + Matrix Multiplication + - uses currentDim +*******************************************************************************/ +// This seems to win for clang +#define auxTriMultiply(a, b, c) (auxTriMultiply_FASTER2((a), (b), (c))) + +static int *offsetArray = NULL; +static void calcOffsetArray(int dim); + +// Standard matrix multiplication where: result = ma * mb +// - The result is pre-allocated and distinct from ma or mb. +// - the actual multiplications are performed by auxExecMultiply +void multiply(Matrix_t *result, Matrix_t *ma, Matrix_t *mb) { + req_NonNull(ma); + req_NonNull(mb); + req_NonNull(result); + req_Distinct(ma, result); + req_Distinct(mb, result); + + int aDim = ma->dimension; + int bDim = mb->dimension; + int dim = result->dimension; + + if (aDim != dim || bDim != dim) { + diagnostic("multiply: Matrix arguments have different dimension"); + error_exit(); + } + if (ma->isTriangular && mb->isTriangular) { + auxTriMultiply(result, ma, mb); + return; + } + + fullMultiply(result, ma, mb); + +} + +void stdMultiply(Matrix_t *result, Matrix_t *ma, Matrix_t *mb) { + req_NonNull(ma); + req_NonNull(mb); + req_NonNull(result); + req_Distinct(ma, result); + req_Distinct(mb, result); + + int aDim = ma->dimension; + int bDim = mb->dimension; + int dim = result->dimension; + + if (aDim != dim || bDim != dim) { + diagnostic("stdMultiply: Matrix arguments have different dimension"); + error_exit(); + } + + fullMultiply(result, ma, mb); +} + +/* +void inline triMultiplyStd(Matrix_t *result, Matrix_t *ma, Matrix_t *mb) { + auxTriMultiply_STANDARD(result, ma, mb); +} + +void inline triMultiplyFAST(Matrix_t *result, Matrix_t *ma, Matrix_t *mb) { + auxTriMultiply_FAST(result, ma, mb); +} + +void inline triMultiplyFAST2(Matrix_t *result, Matrix_t *ma, Matrix_t *mb) { + auxTriMultiply_FAST2(result, ma, mb); +} + +void inline triMultiplyFASTER(Matrix_t *result, Matrix_t *ma, Matrix_t *mb) { + auxTriMultiply_FASTER(result, ma, mb); +} + +void inline triMultiplyFASTER2(Matrix_t *result, Matrix_t *ma, Matrix_t *mb) { + auxTriMultiply_FASTER2(result, ma, mb); +} + +void inline triMultiplyFASTER3(Matrix_t *result, Matrix_t *ma, Matrix_t *mb) { + auxTriMultiply_FASTER3(result, ma, mb); +} + +void inline triMultiplyFASTER4(Matrix_t *result, Matrix_t *ma, Matrix_t *mb) { + auxTriMultiply_FASTER4(result, ma, mb); +} + +void inline triMultiplyFASTER5(Matrix_t *result, Matrix_t *ma, Matrix_t *mb) { + auxTriMultiply_FASTER5(result, ma, mb); +} +*/ + +// Full Square matrix multiplication +static inline void fullMultiply(Matrix_t *result, Matrix_t *ma, Matrix_t *mb) { + int dim = result->dimension; + + Byte_t *array = result->array; + Byte_t *aArray = ma->array; + Byte_t *bArray = mb->array; + + int posn = 0; + for (int row = 0; row < dim; row++) { + for (int col = 0; col < dim; col++) { + array[posn] = dotProduct(aArray, bArray, dim, row, col); + posn += 1; + } + } +} + +/* +// Triangular matrix multiplication: +// - both arguments ma and mb are upper triangular +// - The result is pre-allocated and distinct from ma or mb. +static void auxTriMultiply_STANDARD(Matrix_t *result, Matrix_t *ma, Matrix_t *mb) { + int dim = result->dimension; + + Byte_t *array = result->array; + + Byte_t *aArray = ma->array; + Byte_t *bArray = mb->array; + + // Now traverse the array + int posn = 0; + for (int row = 0; row < dim; row++) { + for (int col = 0; col < dim; col++) { + + // upper triangular matrix multiplication + if (row > col) { + // lower triangular elements are zero + array[posn] = 0; + } + else if (row == col) { + // leading diaagonal elements are one + array[posn] = 1; + } + else { + // upper triangular elements + array[posn] = dotProduct(aArray, bArray, dim, row, col); + } + + posn += 1; + } + } + + result-> isTriangular = TRUE; +} + + +// Triangular matrix multiplication: +// - both arguments ma and mb are upper triangular +// - exploits that lower half a triangular matrix is fixed ... +static void auxTriMultiply_FAST(Matrix_t *result, Matrix_t *ma, Matrix_t *mb) { + int dim = result->dimension; + + if (!result->isTriangular) { + setIdentityMatrix(result); + } + + Byte_t *array = result->array; + + Byte_t *aArray = ma->array; + Byte_t *bArray = mb->array; + + // Iteration over the upper triangular part of the array ... + // Calculates position ... + int posn = 1; + for (int col = 1; col < dim; col++) { + posn = col; + for (int row = 0; row < col; row++) { + array[posn] = dotProduct(aArray, bArray, dim, row, col); + posn += dim; + } + } +} + + +// Triangular matrix multiplication: +// - both arguments ma and mb are upper triangular +// - exploits that lower half a triangular matrix is fixed ... +static void auxTriMultiply_FAST2(Matrix_t *result, Matrix_t *ma, Matrix_t *mb) { + int dim = result->dimension; + + if (!result->isTriangular) { + setIdentityMatrix(result); + } + + Byte_t *array = result->array; + + Byte_t *aArray = ma->array; + Byte_t *bArray = mb->array; + + // Iteration over the upper triangular part of the array ... + // Proceeds linearly row-by-row and then col-by-col ... + // - Corresponds to a linear scan + int posn = 0; + //int rowStart = 0; + for (int row = 0; row < dim; row++) { + posn += row+1; + // rowStart = posn; + for (int col = row+1; col < dim; col++) { + array[posn] = dotProduct(aArray, bArray, dim, row, col); + posn += 1; + } + } +} + +// Triangular matrix multiplication: +// - both arguments ma and mb are upper triangular +// - exploits the fact the half a triangular matrix is fixed ... +static void auxTriMultiply_FASTER(Matrix_t *result, Matrix_t *ma, Matrix_t *mb) { + int dim = result->dimension; + + if (dim != currentDim || offsetArray == NULL) { + calcOffsetArray(dim); + } + + if (!result->isTriangular) { + setIdentityMatrix(result); + } + + Byte_t *array = result->array; + Byte_t *aArray = ma->array; + Byte_t *bArray = mb->array; + + // Iteration over the upper triangular part of the array ... + // Calculates position ... + int posn = 1; + for (int col = 1; col < dim; col++) { + posn = col; + for (int row = 0; row < col; row++) { + array[posn] = dotProduct_Tri(aArray, bArray, dim, posn, row, col); + posn += dim; + } + } +} +*/ + +// Triangular matrix multiplication: +// - both arguments ma and mb are upper triangular +// - exploits the fact the half a triangular matrix is fixed ... +static void auxTriMultiply_FASTER2(Matrix_t *result, Matrix_t *ma, Matrix_t *mb) { + int dim = result->dimension; + + if (!result->isTriangular) { + setIdentityMatrix(result); + } + + Byte_t *array = result->array; + Byte_t *aArray = ma->array; + Byte_t *bArray = mb->array; + + // Iteration over the upper triangular part of the array ... + // Calculates position ... + int posn = 0; + int rowStart = 0; + for (int row = 0; row < dim; row++) { + posn += row+1; + rowStart = posn; + for (int col = row+1; col < dim; col++) { + //array[posn] = dotProduct(aArray, bArray, dim, row, col); + array[posn] = dotProduct_Tri2(aArray, bArray, dim, rowStart, posn, row, col); + posn += 1; + } + } +} + + +/* +// Triangular matrix multiplication: +// - both arguments ma and mb are upper triangular +// - exploits the fact the half a triangular matrix is fixed ... +static void auxTriMultiply_FASTER3(Matrix_t *result, Matrix_t *ma, Matrix_t *mb) { + int dim = result->dimension; + + if (!result->isTriangular) { + setIdentityMatrix(result); + } + + Byte_t *array = result->array; + Byte_t *aArray = ma->array; + Byte_t *bArray = mb->array; + + // Iteration over the upper triangular part of the array ... + // Calculates position ... + int posn = 0; + int rowStart = 0; + for (int row = 0; row < dim; row++) { + posn += row+1; + rowStart = posn; + for (int col = row+1; col < dim; col++) { + //xdebug("auxTriMultiply_FASTER3(row=%i, col=%i, posn=%i, rowStart=%i\n", row, col, posn, rowStart); + //array[posn] = dotProduct(aArray, bArray, dim, row, col); + array[posn] = dotProduct_Tri3(aArray, bArray, dim, rowStart, posn, row, col); + posn += 1; + } + } +} + +// Triangular matrix multiplication: +// - both arguments ma and mb are upper triangular +// - exploits the fact the half a triangular matrix is fixed ... +static void auxTriMultiply_FASTER4(Matrix_t *result, Matrix_t *ma, Matrix_t *mb) { + int dim = result->dimension; + + if (!result->isTriangular) { + setIdentityMatrix(result); + } + + Byte_t *array = result->array; + Byte_t *aArray = ma->array; + Byte_t *bArray = mb->array; + + // Iteration over the upper triangular part of the array ... + // Calculates position ... + int posn = 0; + int rowStart = 0; + for (int row = 0; row < dim; row++) { + posn += row+1; + rowStart = posn; + for (int col = row+1; col < dim; col++) { + //xdebug("auxTriMultiply_FASTER4(row=%i, col=%i, posn=%i, rowStart=%i\n", row, col, posn, rowStart); + //array[posn] = dotProduct(aArray, bArray, dim, row, col); + array[posn] = dotProduct_Tri4(aArray, bArray, dim, rowStart, posn, row, col); + posn += 1; + } + } +} + + +// Triangular matrix multiplication: +// - both arguments ma and mb are upper triangular +// - exploits the fact the half a triangular matrix is fixed ... +static void auxTriMultiply_FASTER5(Matrix_t *result, Matrix_t *ma, Matrix_t *mb) { + int dim = result->dimension; + + if (!result->isTriangular) { + setIdentityMatrix(result); + } + + Byte_t *array = result->array; + Byte_t *aArray = ma->array; + Byte_t *bArray = mb->array; + + // Iteration over the upper triangular part of the array ... + // Calculates position ... + int posn = 0; + int rowStart = 0; + for (int row = 0; row < dim; row++) { + posn += row+1; + rowStart = posn; + for (int col = row+1; col < dim; col++) { + //xdebug("auxTriMultiply_FASTER5(row=%i, col=%i, posn=%i, rowStart=%i\n", row, col, posn, rowStart); + //array[posn] = dotProduct(aArray, bArray, dim, row, col); + array[posn] = dotProduct_Tri5(aArray, bArray, dim, rowStart, posn, row, col); + posn += 1; + } + } +} +*/ + +/******************************************************************************* + Dot Products + - as used in Matrix Multiplication + - special cases for upper triangular matrices +*******************************************************************************/ +// Standard dot product +static Byte_t dotProduct(Byte_t *aArray, Byte_t *bArray, int dim, int row, int col) { + Byte_t result = 0; + + int aPosn = row*dim; // starting position for row ... + int bPosn = col; // starting position for col ... + + int aVal, bVal; + + for (int k = 0; k < dim; k++) { + // current values + aVal = aArray[aPosn]; + bVal = bArray[bPosn]; + + // update positions + aPosn += 1; + bPosn += dim; + + // update result ... + if (aVal == 0 || bVal == 0) continue; + + if (aVal == 1) { + result += bVal; + } + else if (bVal == 1) { + result += aVal; + } +// else if (aVal != 0 && bVal != 0) { + else { + result += (Byte_t)(aVal * bVal); + } + } + + return (Byte_t)result; +} + +/* +// "Triangular" form of dot product. +// - Assumes that the dot product is computed in the (strictly) upper triangular part of matrix +// - - the row start is precomputed in the given offset array +static Byte_t dotProduct_Tri(Byte_t *aArray, Byte_t *bArray, int dim, int posn, int row, int col) { + Byte_t result = aArray[posn] + bArray[posn]; + + int aPosn = offsetArray[row]; + //int aPosn = row*(dim + 1) + 1; // first off-diagonal element in current row + int bPosn = posn+dim; // first column eement beyond posn i.e. (row+1, col) + + //xdebug(" dotProduct LOOP START: aPosn = %i bPosn = %i", aPosn, bPosn); + + while (aPosn < posn) { + result += (Byte_t)(aArray[aPosn] * bArray[bPosn]); + + //xdebug(""); + //xdebug(" dotProduct LOOP: k = %i", k); + //xdebug(" dotProduct LOOP: a(%i, %i) aPosn = %i aVal = %i )", row, k, aPosn, aVal); + //xdebug(" dotProduct LOOP: b(%i, %i) bPosn = %i bVal = %i", k, col, bPosn, bVal); + + aPosn += 1; + bPosn += dim; + + //xdebug(" dotProduct LOOP: result (so far) = %i", (Byte_t)result); + } + + //xdebug(""); + //xdebug(" dotProduct END: ma = %p mb = %p row = %i col = %i", (void *)ma, (void *)mb, row, col); + //xdebug(" dotProduct END: result = %i", (Byte_t)result); + + return (Byte_t)result; +} + +static void calcOffsetArray(int dim) { + free(offsetArray); + + offsetArray = ALLOC_ARR(dim, int); + + for (int i = 0; i < dim; i++) { + offsetArray[i] = i*(dim+1) + 1; + } + + currentDim = dim; +} +*/ + +// "Triangular" form of dot product. +// - Assumes that the dot product is computed in the (strictly) upper triangular part of matrix +// - +static Byte_t dotProduct_Tri2(Byte_t *aArray, Byte_t *bArray, int dim, int rowStart, int posn, int row, int col) { + Byte_t result = aArray[posn] + bArray[posn]; + + int aPosn = rowStart; + //int aPosn = row*(dim + 1) + 1; // first off-diagonal element in current row + int bPosn = posn+dim; // first column element beyond posn i.e. (row+1, col) + + + while (aPosn < posn) { + result += (Byte_t)(aArray[aPosn] * bArray[bPosn]); + + aPosn += 1; + bPosn += dim; + } + + return (Byte_t)result; +} + +/* +// "Triangular" form of dot product. +// - Assumes that the dot product is computed in the (strictly) upper triangular part of matrix +// - +static Byte_t dotProduct_Tri3(Byte_t *aArray, Byte_t *bArray, int dim, int rowStart, int posn, int row, int col) { + Byte_t result = aArray[posn] + bArray[posn]; + + int aPosn = rowStart; + //int aPosn = row*(dim + 1) + 1; // first off-diagonal element in current row + int bPosn = posn+dim; // first column element beyond posn i.e. (row+1, col) + + + while (aPosn < posn) { + result += byteMult(aArray[aPosn] , bArray[bPosn]); + + aPosn += 1; + bPosn += dim; + } + + return (Byte_t)result; +} + + +// "Triangular" form of dot product. +// - Assumes that the dot product is computed in the (strictly) upper triangular part of matrix +// - +static Byte_t dotProduct_Tri4(Byte_t *aArray, Byte_t *bArray, int dim, int rowStart, int posn, int row, int col) { + Byte_t result = aArray[posn] + bArray[posn]; + + int aPosn = rowStart; // first off-diagonal element in current row + int bPosn = posn+dim; // first column element beyond posn i.e. (row+1, col) + + Byte_t *aP = (aArray + aPosn); + Byte_t *bP = (bArray + bPosn); + + while (aPosn < posn) { + result += (*aP * *bP); + + aP += 1; + bP += dim; + + aPosn += 1; + } + + return result; +} + +// "Triangular" form of dot product. +// - Assumes that the dot product is computed in the (strictly) upper triangular part of matrix +// - +static Byte_t dotProduct_Tri5(Byte_t *aArray, Byte_t *bArray, int dim, int rowStart, int posn, int row, int col) { + Byte_t result = aArray[posn] + bArray[posn]; + + int aPosn = rowStart; // first off-diagonal element in current row + int bPosn = posn+dim; // first column element beyond posn i.e. (row+1, col) + + Byte_t *aP = (aArray + aPosn); + Byte_t *bP = (bArray + bPosn); + + while (aPosn < posn) { + result += byteMult(*aP , *bP); + + aP += 1; + bP += dim; + + aPosn += 1; + } + + return result; +} +*/ + +/******************************************************************************* + Power of matrix +*******************************************************************************/ + +static LinearMap_t* powerOfMemoMap = NULL; // basic memoisation + +static void initPowerOfMemoMap(Matrix_t *ma) { + if (powerOfMemoMap == NULL) { + powerOfMemoMap = new_LM(deallocateMatrix); + } + else { + clear_LM(powerOfMemoMap); + } +} + +void powerOfMatrix(Matrix_t *result, Matrix_t *ma, int power) { + req_NonNull(result); + req_NonNull(ma); + + initPowerOfMemoMap(ma); + + if (ma->isTriangular) { + auxTriPowerOf(result, ma, power); + } + else { + auxPowerOf(result, ma, power); + } +} + + +static void auxTriPowerOf(Matrix_t *result, Matrix_t *ma, int power) { + int dim = ma->dimension; + + // check for trivial results + if (power == 0) { + setIdentityMatrix(result); + return; + } + else if (power == 1) { + // unit case + cloneMatrix(result, ma); + return; + } + + // check memoMap for previous entry + Matrix_t *memoMatrix = getEntry_LM(powerOfMemoMap, power); + if (memoMatrix != NULL) { + cloneMatrix(result, memoMatrix); + return; + } + + // calculate the result + if (power % 2 == 0) { + // even powers case + int halfPower = power / 2; // int division + + Matrix_t *tempMat = allocateTriMatrix(dim); + auxTriPowerOf(tempMat, ma, halfPower); + + auxTriMultiply(result, tempMat, tempMat); + + deallocateMatrix(tempMat); + } + else { + // odd powers case + int halfPower = power / 2; // int division + + Matrix_t *tempMat1 = allocateTriMatrix(dim); + auxTriPowerOf(tempMat1, ma, halfPower); + + Matrix_t *tempMat2 = allocateTriMatrix(dim); + auxTriMultiply(tempMat2, tempMat1, tempMat1); + auxTriMultiply(result, ma, tempMat2); + + deallocateMatrix(tempMat1); + deallocateMatrix(tempMat2); + } + + // add the result into the memo map + Matrix_t *cloneResult = allocateTriMatrix(dim); + cloneMatrix(cloneResult, result); + addEntry_LM(powerOfMemoMap, power, cloneResult); +} + + +static void auxPowerOf(Matrix_t *result, Matrix_t *ma, int power) { + int dim = ma->dimension; + + if (power == 0) { + setIdentityMatrix(result); + } + else if (power == 1) { + // unit case + cloneMatrix(result, ma); + } + + // check memoMap for previous entry + Matrix_t *memoMatrix = getEntry_LM(powerOfMemoMap, power); + if (memoMatrix != NULL) { + cloneMatrix(result, memoMatrix); + return; + } + + if (power % 2 == 0) { + // even powers case + int halfPower = power / 2; // int division + + Matrix_t *tempMat = allocateMatrix(dim, FALSE); + auxPowerOf(tempMat, ma, halfPower); + + fullMultiply(result, tempMat, tempMat); + + deallocateMatrix(tempMat); + } + else { + // odd powers case + int halfPower = power / 2; // int division + + Matrix_t *tempMat1 = allocateMatrix(dim, FALSE); + auxPowerOf(tempMat1, ma, halfPower); + + Matrix_t *tempMat2 = allocateMatrix(dim, FALSE); + fullMultiply(tempMat2, tempMat1, tempMat1); + fullMultiply(result, ma, tempMat2); + + deallocateMatrix(tempMat1); + deallocateMatrix(tempMat2); + } + + // add the result into the memo map + Matrix_t *cloneResult = allocateMatrix(dim, FALSE); + cloneMatrix(cloneResult, result); + addEntry_LM(powerOfMemoMap, power, cloneResult); +} + + +/******************************************************************************* + Calculate periods and inverses (when exists). +*******************************************************************************/ + +static Matrix_t *inverseMatrix = NULL; + +static void initInverseCalc(Matrix_t *ma) { + req_NonNull(ma); + + int dim = ma->dimension; + + deallocateMatrix(inverseMatrix); // release current inverse matrix - allows for reset dimension + inverseMatrix = allocateMatrix(dim, FALSE); // initialises to zero matrix +} + + +// Calculates period of matrix +// - if ma is triangular, its period is always a power of two (i.e. divisor of size of group). +int periodOfMatrix(Matrix_t *ma) { + req_NonNull(ma); + + // initialises inverse calculation + initInverseCalc(ma); + + if (isIdentityMatrix(ma)) { + cloneMatrix(inverseMatrix, ma); + return 1; + } + + // Matrix is non-trivial + return ( ma->isTriangular + ? auxTriPeriodOfMatrix(ma) + : auxPeriodOfMatrix(ma) + ); +} + +// Calculates inverse, by using the period, if it exists. +void inverseOfMatrix(Matrix_t *result, Matrix_t *source) { + req_NonNull(source); + req_NonNull(result); + + setZeroMatrix(result); + + int period = periodOfMatrix(source); + + if (period >= 1) { + cloneMatrix(result, inverseMatrix); + } +} + + +static int auxTriPeriodOfMatrix(Matrix_t *ma) { + int dim = ma->dimension; + int count = 1; + int result = -1; + + // Exploits triangular property ... + Matrix_t *prevProduct = allocateTriMatrix(dim); // initialises to identity + Matrix_t *curProduct = allocateTriMatrix(dim); // initialises to identity + + Matrix_t *accumMatrix = allocateTriMatrix(dim); // initialises to identity + Matrix_t *prevAccumMatrix = allocateTriMatrix(dim); // initialises to identity + + // sets curProduct to initial matrix + cloneMatrix(curProduct, ma); + + while (TRUE) { + swopMatrices(curProduct, prevProduct); // swops content + swopMatrices(accumMatrix, prevAccumMatrix); // swops content + + // repeated squaring + count *= 2; + auxTriMultiply(curProduct, prevProduct, prevProduct); + + // accumulate product: (2^p - 1) = 1 + 2^1 + 2^2 + ... + 2^(p-1) + // - this calculates the inverse (at end of calc). + auxTriMultiply(accumMatrix, prevAccumMatrix, curProduct); + + // test + if (isIdentityMatrix(curProduct)) { + cloneMatrix(inverseMatrix, accumMatrix); + result = count; + break; + } + else if (count >= MAX_PERIOD_LIMIT) { + break; + } + } + + // release temp resources + deallocateMatrix(prevProduct); + deallocateMatrix(curProduct); + + deallocateMatrix(accumMatrix); + deallocateMatrix(prevAccumMatrix); + + return result; +} + + +static int auxPeriodOfMatrix(Matrix_t *ma) { + int dim = ma->dimension; + int count = 1; + int result = -1; + + Matrix_t *prevProduct = allocateMatrix(dim, FALSE); + Matrix_t *curProduct = allocateMatrix(dim, FALSE); + + cloneMatrix(curProduct, ma); + + while (TRUE) { + // swop around matrices + swopMatrices(curProduct, prevProduct); + + // iterate curProduct + count += 1; + fullMultiply(curProduct, prevProduct, ma); + + if (isIdentityMatrix(curProduct)) { + // if curProduct is the identity + // - then prevProduct is the inverse!! + cloneMatrix(inverseMatrix, prevProduct); + result = count; + + } + else if (isZeroMatrix(curProduct)) { + break; + } + else if (count >= MAX_PERIOD_LIMIT) { + break; + } + } + + // release temp resources + deallocateMatrix(prevProduct); + deallocateMatrix(curProduct); + + return result; +} + + +/******************************************************************************* + Disposal of matrix + - disposes of underlying matrix memory and the objects ... +*******************************************************************************/ + +static void disposeMatrix(void *obj) { + req_NonNull(obj); + + Matrix_t *ma = (Matrix_t *)obj; + + // free the allocated array + free(ma->array); + ma->array = NULL; + + // Now free the Matrix_t element + free(ma); +} + + +/******************************************************************************* + Fingerprinting of matrix +*******************************************************************************/ +char *showMatrixFingerprint(Matrix_t *matrix, int fpLength) { + req_NonNull(matrix); + + ByteVec_t *tempBV = new_BV(); + extractContent(tempBV, matrix); + + // calc. fingerprint of tempBV (i.e. matrix content) + char *result = showFingerprint_BV(tempBV, fpLength); + deallocate_BV(tempBV); + + return result; +} + + +/******************************************************************************* + Show/Display matrices +*******************************************************************************/ + +// Extracts matrix entries to stringbuffer ... +// - adds string repn. into given string buffer +// - entries are given as decimal byte values +void showMatrix(Matrix_t *ma, StringBuf_t *sBuf, char *indent) { + auxShowMatrix("%-3u ", ma, sBuf, indent); +} + + +// Extracts matrix entries to stringbuffer ... +// - adds string repn. into given string buffer. +// - entries are given as hex byte values +void showMatrixHex(Matrix_t *ma, StringBuf_t *sBuf, char *indent) { + auxShowMatrix("%02x ", ma, sBuf, indent); +} + + +static void auxShowMatrix(const char *fmt, Matrix_t *ma, StringBuf_t *sBuf, char *indent) { + req_NonNull(ma); + req_NonNull(sBuf); + + int dim = ma->dimension; + int size = ma->capacity; + ensureCapacity_SB(sBuf, 4*size); + + Byte_t *array = ma->array; + + indent = (isa_Null(indent) ? " " : indent); + int posn = 0; + for (int row = 0; row < dim; row++) { + auxStartOfRow(sBuf, row, indent); + + for (int col = 0; col < dim; col++) { + addUIntF_SB(sBuf, fmt, array[posn]); + posn += 1; + } + } + + addStringF_SB(sBuf, "\n%s]\n", indent); +} + + +static void auxStartOfRow(StringBuf_t *sBuf, int row, char *indent) { + + addString_SB(sBuf, "\n"); + addString_SB(sBuf, indent); + if (row == 0) { + addString_SB(sBuf, "[ "); + } + else { + addString_SB(sBuf, " "); + } +} + + +// Useful debugging aid for displaying matrices +static StringBuf_t *debugSB = NULL; +char *debugMatrix(Matrix_t *ma) { + if (! debugOn) return ""; + + if (ma == NULL) { + diagnostic("debugMatrix : Null matrix pointer ..."); + codeError_exit(); + } + + if (debugSB == NULL) { + debugSB = allocate_SB(MSG_BUFSIZE+1); + } + else { + reset_SB(debugSB); + } + + showMatrixHex(ma, debugSB, ">>>> "); + + return (char *)getContent_BV(debugSB); +} + +char *xdebugMatrix(Matrix_t *ma) { + return ""; +} + + +/******************************************************************************* + Dump matrix info ... (debugging aid ...) +*******************************************************************************/ +static StringBuf_t *dumpSB = NULL; +char *dump_Matrix(Matrix_t *ma, char *offset) { + if (ma == NULL) { + diagnostic("dump_Matrix : Null matrix pointer ..."); + codeError_exit(); + } + + // ensure defined + if (dumpSB == NULL) { + dumpSB = allocate_SB(MSG_BUFSIZE+1); + } + else { + reset_SB(dumpSB); + } + + addItems_SB(dumpSB, "%sMatrix_t (0x%lu)\n", offset, (Ptr_t)ma); + addItems_SB(dumpSB, "%s dimension: %i\n", offset, ma->dimension); + addItems_SB(dumpSB, "%s capacity: %i\n", offset, ma->capacity); + addItems_SB(dumpSB, "%s isTriangular: %s\n", offset, showBoolean(ma->isTriangular)); + addItems_SB(dumpSB, "%s array: 0x%lu\n", offset, (Ptr_t)ma->array); + + return (char *)getContent_BV(dumpSB); +} diff --git a/hash_fusion/lib/matrix.h b/hash_fusion/lib/matrix.h new file mode 100644 index 0000000000..6d17caa376 --- /dev/null +++ b/hash_fusion/lib/matrix.h @@ -0,0 +1,196 @@ +#ifndef __MATRIX_H__ +#define __MATRIX_H__ + +/* + matrix.h + + This library defines some basic matrix operations over square integer + matrices, where the entries of these matrices are all Byte_t entries. + + In particular his package provides special code for processing upper triangular matrices + (with unit diagonal). + + Author: brian.monahan@hpe.com + + (c) Copyright 2017 Hewlett Packard Enterprise Development LP + + 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. + + 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. +*/ + +#include "utils.h" +#include "bytevector.h" +#include "stringbuffer.h" + +typedef struct matrix Matrix_t; + +//const int sizeof_MATRIX; + +// Allocates matrix of given dimension and triangularity +// - can specify dimension of matrix (if 0 then uses currentDim). +// - can specify triangular. +// - if triangular, sets matrix as identity +// - otherwise, zeroes the matrix +Matrix_t *allocateMatrix(int dim, Boolean_t isTriangular); +Matrix_t *allocateTriMatrix(int dim); + +// resets the given matrix appropriately +// - can specify dimension of matrix. +// - can specify triangular. +// - if triangular, sets matrix as identity +// - otherwise, zeroes the matrix +void resetMatrix(Matrix_t *ma, int dim, Boolean_t isTriangular); + +// deallocates given matrix by recycling ... +void deallocateMatrix(void *obj); + +// get/set current dimension +int getCurrentDim(); +void setCurrentDim(int dim); + +// Resets a given matrix as an zero matrix +// - unsets the triangular property +void setZeroMatrix(Matrix_t *ma); + +// Resets a given matrix as an identity matrix +// - sets triangular property +void setIdentityMatrix(Matrix_t *ma); + +// Get value ... +// - checks array bounds +Byte_t getValue(Matrix_t *ma, int col, int row); + +// Set value +// - checks array bounds +void setValue(Matrix_t *ma, int col, int row, Byte_t newVal); + +// gets the dimension of the given matrix ... +int getDimension(Matrix_t *a); + +// returns if matrix is triangular +Boolean_t isTriangular(Matrix_t *a); + +// independent check that matrix is triangular +Boolean_t checkTriangular(Matrix_t *a); + +// Returns the max number of elements available in matrix +// - For upper triangular, this does not include the diagonal or the lower +// triangular elements. +int maxElemsMatrix(Matrix_t *mat); + +// triangular number i.e. number of elems above leading diagonal of matrix of size dim. +int triNumber(int dim); + +// Calculates the dimension of the smallest upper triangular matrix to contain content +// of given length. +int calcDimension(int length); + +// Calculates the size of the zero padding for a vector of given length. +int calcPadding(int length); + +// Extracts content from given matrix and copies it into the given bytevector. +// - if the bytevector's data vector is NULL, then fresh memory is allocated to fit. +// - if the matrix is triangular, the upper triangular portion of the matrix is captured. +void extractContent(ByteVec_t *dest, Matrix_t *source); + +// Copies the bytevector content into given matrix ... +// - mapping takes into account if matrix is triangular +void insertContent(Matrix_t *dest, ByteVec_t *content); + +// Swops two matrices pointed at by ma and mb +// - both ma and mb must have the same triangular property ... +void swopMatrices(Matrix_t *ma, Matrix_t *mb); + +// Copies the content of the given matrix into the dest matrix. +// - Clobbers the content of the destination matrix ... +// - The destination matrix resets transpose status. +void cloneMatrix(Matrix_t *dest, Matrix_t *source); + + +// Test equality of matrices +Boolean_t equalMatrix(Matrix_t *ma, Matrix_t *mb); + + +// Test if matrix is the identity +Boolean_t isIdentityMatrix(Matrix_t *ma); + + +// Test if matrix is zero +Boolean_t isZeroMatrix(Matrix_t *ma); + + +// Randomised matrix in given matrix +void randomMatrix(Matrix_t *dest); + + +// Calculate the matrix made by raising matrix ma to the specified power +// - recursive mechanism - needs temporary matrices ... +void powerOfMatrix(Matrix_t *result, Matrix_t *ma, int power); + + +// Standard matrix multiplication where: result = ma * mb +// - Result is an existing matrix and assumed to be distinct from ma or mb. +// - internally optimises for triangular matrices +void multiply(Matrix_t *result, Matrix_t *ma, Matrix_t *mb); // has special case for triangular +void stdMultiply(Matrix_t *result, Matrix_t *ma, Matrix_t *mb); // no special case for triangular + +/* +// Code to find fast triangular multiply +void triMultiplyFAST(Matrix_t *result, Matrix_t *ma, Matrix_t *mb); +void triMultiplyFAST2(Matrix_t *result, Matrix_t *ma, Matrix_t *mb); +void triMultiplyFASTER(Matrix_t *result, Matrix_t *ma, Matrix_t *mb); +void triMultiplyFASTER2(Matrix_t *result, Matrix_t *ma, Matrix_t *mb); // fastest for clang +void triMultiplyFASTER3(Matrix_t *result, Matrix_t *ma, Matrix_t *mb); +void triMultiplyFASTER4(Matrix_t *result, Matrix_t *ma, Matrix_t *mb); +void triMultiplyFASTER5(Matrix_t *result, Matrix_t *ma, Matrix_t *mb); +*/ + +// Calculates period of matrix +// - if triangular, period is non-zero and always a power of two +int periodOfMatrix(Matrix_t *ma); + + +// Calculates inverse (by using the period, if it exists). +void inverseOfMatrix(Matrix_t *result, Matrix_t *source); + + +// Show matrix fingerprint ... +char *showMatrixFingerprint(Matrix_t *matrix, int fpLength); + + +// Extracts matrix entries to string ... +// - places string into given pre-allocated output string. +// - entries are given as decimal byte values (i.e. unsigned) +void showMatrix(Matrix_t *ma, StringBuf_t *sBuf, char *offset); + + +// Print matrix to string (in Hex)... +// - places string into given pre-allocated string. +// - entries are given as decimal byte values (i.e. unsigned) +void showMatrixHex(Matrix_t *ma, StringBuf_t *sBuf, char *offset); + +// Useful debugging aid for displaying matrices +char *debugMatrix(Matrix_t *ma); +char *xdebugMatrix(Matrix_t *ma); + +#endif diff --git a/hash_fusion/lib/merkleTree.c b/hash_fusion/lib/merkleTree.c new file mode 100644 index 0000000000..e8dd93a187 --- /dev/null +++ b/hash_fusion/lib/merkleTree.c @@ -0,0 +1,1189 @@ +/* merkleTree.c + + An Implementation of Merkle Trees + + Merkle Tree + - Standard Peer-2-Peer hashing of a sequence of blocks + - Handles building of data sequence in random order ... + - Merkle, R. C. (1988). "A Digital Signature Based on a Conventional Encryption Function". + Advances in Cryptology — CRYPTO '87. Lecture Notes in Computer Science 293. p. 369 + + Author: brian.monahan@hpe.com + + (c) Copyright 2017 Hewlett Packard Enterprise Development LP + + 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. + + 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. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "alloc.h" +#include "hashlib.h" +#include "merkleTree.h" + + +// Merkle Tree Structures +// - Two kinds of node - internal nodes and leaf nodes. +typedef void MTreeNode_t; // generic tree node type - covers (internal) node and leaf structs. + +typedef struct mLeaf MLeaf_t; // Leaf node type +typedef struct mNode MNode_t; // (internal) node type + + +// Root Merkle Tree object +struct merkleTree { + HashSpec_t hashSpec; // Type of HashSpec + Digest_t *topHash; // Final digest value -- weak reference (NO allocation) + int blockCount; // Current total of data blocks + int maxPosition; // Max position + int height; // Total height of tree + int totalNodes; // Total number of tree nodes (i.e. both internal nodes and leaves) + Boolean_t autoClean; // if TRUE, deallocates nodes as soon as possible. + MTreeState_t state; // Current state + MTreeNode_t *treeRoot; // Tree nodes ... +}; + +// Define tag values for the two different kinds of tree node. +// - tag values are always the first byte of object ... (see utils.h) +#define TAG_MLeaf_t (Tag_t)'L' +#define TAG_MNode_t (Tag_t)'N' + +// Tag checks +#define isLeaf(obj) (checkTag((obj), TAG_MLeaf_t)) +#define isNode(obj) (checkTag((obj), TAG_MNode_t)) + +// Internal nodes +// - have pivots + base +// - these have two sub-trees +struct mNode { + Tag_t tag; // Tag for tree node + int height; // Height of tree + int pivot; // Pivot + int base; // Base + Digest_t *digest; // Digest + MTreeNode_t *left; // Left sub tree + MTreeNode_t *right; // Right sub tree +}; + + +// - Leaf nodes +// + have positions +// + has non-NULL digest +struct mLeaf { + Tag_t tag; // Tag for tree leaf + int position; // Position + Digest_t *digest; // Digest +}; + + +/******************************************************************************* + Memory Management +*******************************************************************************/ +MemMgr_t *merkleTree_MemMgr = NULL; +MemMgr_t *leaf_MemMgr = NULL; +MemMgr_t *node_MemMgr = NULL; + + +/******************************************************************************* + Static method prototypes +*******************************************************************************/ +static void ensureMemMgmt(); + +static MTreeNode_t *allocate_Leaf(MTree_t *mTree, int position, Digest_t *digest); +static MTreeNode_t *allocate_Node(MTree_t *mTree, int height, int base, MTreeNode_t *left, MTreeNode_t *right); + +static void deallocate_TreeNode(MTree_t *mTree, void *obj); +static void deallocate_Node(MTree_t *mTree, MNode_t *obj); +static void deallocate_Leaf(MTree_t *mTree, MLeaf_t *obj); + +static int calcPivot(int height, int base); +static int calcHeight(int position); + +static void setLeft(MTree_t *mTree, MNode_t *node, MTreeNode_t *left); +static void setRight(MTree_t *mTree, MNode_t *node, MTreeNode_t *right); + +static Digest_t *getDigest(MTreeNode_t *item); +static void calcDigest(MTree_t *mTree, MTreeNode_t *item); +static void calcTreeDigest(MTree_t *mTree, MTreeNode_t *item, Boolean_t isComplete); +static void rightmostPromotion(MTree_t *mTree, MNode_t *node); + +static void inflateTree(MTree_t *mTree, int nodeHeight); +static void insertNode(MTree_t *mTree, MTreeNode_t *curNode, MTreeNode_t *newTreeNode); + +// showing tree state +static void initShowTree(StringBuf_t *sbuf); +static void showTree(MTree_t *mTree); +static void resetShowTree(); + +// display node +static char *displayNode(MTreeNode_t *item); + + +/******************************************************************************* + Methods +*******************************************************************************/ + +// The default auto clean +Boolean_t autoCleanDefault = FALSE; + +// New Merkle Tree +MTree_t *new_MT(HashSpec_t hSpec) { + return allocate_MT(hSpec, autoCleanDefault); +} + +MTree_t *allocate_MT(HashSpec_t hSpec, Boolean_t autoClean) { + // ensure that the allocation structures exist ... + ensureMemMgmt(); + + MTree_t *newTree = allocateObject_MM(merkleTree_MemMgr); + + // reset attributes + newTree->hashSpec = hSpec; + newTree->topHash = NULL; // weak reference to top digest (NO allocation!) + newTree->blockCount = 0; + newTree->maxPosition = -1; + newTree->height = 0; + newTree->totalNodes = 0; + newTree->autoClean = FALSE; //autoClean; + newTree->state = MTree_Initial; + newTree->treeRoot = NULL; + + return newTree; +} + + +// Deallocate/recycle Merkle Tree +void deallocate_MT(MTree_t *mTree) { + if (mTree == NULL) return; + + // ensure that the allocation structures exist ... + ensureMemMgmt(); + + // deallocate tree nodes + deallocate_TreeNode(mTree, mTree->treeRoot); + + // nullify elements + mTree->hashSpec = HSP_NULL; + mTree->topHash = NULL; + mTree->blockCount = 0; + mTree->maxPosition = 0; + mTree->height = 0; + mTree->totalNodes = 0; + mTree->autoClean = FALSE; + mTree->state = MTree_NULL; + mTree->treeRoot = NULL; + + deallocateObject_MM(merkleTree_MemMgr, sizeof(MTree_t), mTree); +} + + +// Resets the given hash tree +void reset_MT(MTree_t *mTree, HashSpec_t hSpec) { + req_NonNull(mTree); + + // ensure that the allocation structures exist ... + ensureMemMgmt(); + + // capture autoClean state + Boolean_t autoClean = mTree->autoClean; + + //deallocate tree nodes + deallocate_TreeNode(mTree, mTree->treeRoot); + + // reset attributes + mTree->hashSpec = hSpec; + mTree->topHash = NULL; // weak ref. + mTree->blockCount = 0; + mTree->maxPosition = -1; + mTree->height = 0; + mTree->totalNodes = 0; + mTree->autoClean = autoClean; + mTree->state = MTree_Initial; + mTree->treeRoot = NULL; +} + + +// Gets current Hash Spec +HashSpec_t getHashSpec_MT(MTree_t *mTree) { + req_NonNull(mTree); + + return mTree->hashSpec; +} + +// Gets Top Hash - if defined +// - This clones the mTree's digest object into given digest, dgst. +// - Returns TRUE only if digest was cloned. +Boolean_t getTopHash_MT(Digest_t *dgst, MTree_t *mTree) { + req_NonNull(dgst); + req_NonNull(mTree); + + if (mTree->topHash == NULL || mTree->state != MTree_Final) { + return FALSE; + } + else { + clone_DG(dgst, mTree->topHash); + + return TRUE; + } +} + + +// Get the total number of data blocks so far. +int getNumBlocks_MT(MTree_t *mTree) { + req_NonNull(mTree); + + return mTree->blockCount; +} + +// Get the maximum position used so far +int getMaxPosition_MT(MTree_t *mTree) { + req_NonNull(mTree); + + return mTree->maxPosition; +} + +// Gets the height of the hash tree ... +int getHeight_MT(MTree_t *mTree) { + req_NonNull(mTree); + + return mTree->height; +} + +// Gets the total number of tree nodes (i.e. internal nodes and leaves). +int getTotalNodes_MT(MTree_t *mTree) { + req_NonNull(mTree); + + return mTree->totalNodes; +} + +// Gets the auto clean flag. +// - if TRUE, deallocate tree nodes as soon as possible. +Boolean_t getAutoClean_MT(MTree_t *mTree) { + req_NonNull(mTree); + + return mTree->autoClean; +} + +// Inspect current state ... +MTreeState_t getState_MT(MTree_t *mTree) { + req_NonNull(mTree); + + return mTree->state; +} + +// Show current state ... +char *showState_MT(MTree_t *mTree) { + req_NonNull(mTree); + + // process current state + switch (mTree->state) { + case MTree_NULL: return "NULL state"; + + case MTree_Initial: return "Initialised"; + case MTree_Partial: return "Partial"; + case MTree_Complete: return "Complete"; + case MTree_Final: return "Final"; + + default: + diagnostic("merkleTree.showState_MT : Unknown state: %i\n", mTree->state); + codeError_exit(); + } +} + + +// Show hash tree by appending to stringbuffer +// - set indent string +// - set incrment indent string +// - set compact display +// - set max depth +void show_MT(MTree_t *mTree, StringBuf_t *sbuf) { + req_NonNull(mTree); + req_NonNull(sbuf); + + initShowTree(sbuf); + showTree(mTree); +} + +// show attributes +static char *show_indent = " "; // indent string +static char *show_incrIndent = " ";; // incremental indent +static Boolean_t show_compact_display = FALSE; +static int show_max_depth = -1; + +void setShowIndent_MT(char * indent) { + int indentLen = strlen(indent); + + if (2 <= indentLen && indentLen < MAX_INDENT_LENGTH) { + show_indent = indent; + resetShowTree(); + } + else { + diagnostic("merkleTree.setShowIndent : Bad indent length: %i", indentLen); + codeError_exit(); + } +} + +void setShowIncrIndent_MT(char * indent) { + int indentLen = strlen(indent); + + if (2 <= indentLen && indentLen < MAX_INDENT_LENGTH) { + show_incrIndent = indent; + resetShowTree(); + } + else { + diagnostic("merkleTree.setShowIncrIndent : Bad indent length: %i", indentLen); + codeError_exit(); + } +} + +void setShowCompact_MT(Boolean_t isCompact) { + show_compact_display = asBoolean(isCompact); +} + +// sets max depth +// - giving non-positive value removes constraint +void setShowMaxDepth_MT(int maxDepth) { + show_max_depth = minmax(0, maxDepth, MAX_TREE_HEIGHT); +} + + +/******************************************************************************* + Adding Data Blocks +*******************************************************************************/ +// Add data blocks into tree +// - Requires that the tree has been initialised and has not yet been finalised. +// - position is 1-based and runs from 1 to K +void addDataBlock_MT(MTree_t *mTree, int position, ByteVec_t *dataVec) { + req_NonNull(mTree); + req_Pos(position); + + // Make position 0-based ... + position = position - 1; + + // sanity check + if (mTree->state == MTree_Final) { + diagnostic("merkleTree.addDataBlock_MT : Can't add more data to an already finalised tree"); + codeError_exit(); + } + + // process current state + switch (mTree->state) { + case MTree_NULL: + diagnostic("merkleTree.addDataBlock_MT : Undefined NULL state"); + codeError_exit(); + + case MTree_Initial: break; + case MTree_Partial: break; + case MTree_Complete: break; + case MTree_Final: + diagnostic("merkleTree.addDataBlock_MT : Can't add more data to an already finalised tree"); + codeError_exit(); + + default: + diagnostic("merkleTree.addDataBlock_MT : Unknown state: %i\n", mTree->state); + codeError_exit(); + } + + // Prepare the new block + HashSpec_t hSpec = mTree->hashSpec; + Digest_t *dataDigest = new_DG(hSpec); + + // Calculate dataDigest ... + Boolean_t stat = hashBV_DG(dataDigest, dataVec); + if (!stat) { + diagnostic("merkleTree.addDataBlock_MT : Data hashing failed!"); + codeError_exit(); + } + + // Build new leaf node + MTreeNode_t *newLeaf = allocate_Leaf(mTree, position, dataDigest); + + // Inflate tree to correct height + // - if the tree is already of sufficient height, then no change. + // - else extends tree from the root + inflateTree(mTree, calcHeight(position)); + + // Insert new node into tree of correct height ... + insertNode(mTree, mTree->treeRoot, newLeaf); + + // Update the number of blocks + mTree->blockCount += 1; + + // Update the max position + mTree->maxPosition = max(mTree->maxPosition, position); + + // update state + Boolean_t isComplete = (mTree->maxPosition + 1 == mTree->blockCount); + mTree->state = (isComplete ? MTree_Complete : MTree_Partial); +} + + +// Finalise the tree (if possible) +// - When complete, determines the full tree digest ... +// - Returns true if successfully finalised, otherwise false. +Boolean_t finalise_MT(MTree_t *mTree) { + req_NonNull(mTree); + + // process current state + switch (mTree->state) { + case MTree_NULL: + diagnostic("merkleTree.finalise_MT : Undefined NULL state"); + codeError_exit(); + case MTree_Initial: return FALSE; + case MTree_Partial: break; + case MTree_Complete: break; + case MTree_Final: return TRUE; + default: + diagnostic("merkleTree.finalise_MT : Unknown state: %i\n", mTree->state); + codeError_exit(); + } + + Boolean_t isComplete = (mTree->maxPosition+1 == mTree->blockCount); + + if (isComplete) { + calcTreeDigest(mTree, mTree->treeRoot, TRUE); + + Digest_t *rootDigest = getDigest(mTree->treeRoot); + + if (rootDigest == NULL) { + return FALSE; + } + else { + mTree->topHash = rootDigest; // getTopHash_MT clones this value. + mTree->state = MTree_Final; + + return TRUE; + } + } + + return FALSE; +} + +/******************************************************************************* + Static methods +*******************************************************************************/ +static void ensureMemMgmt() { + if (merkleTree_MemMgr == NULL) { + merkleTree_MemMgr = new_MM(sizeof(MTree_t)); + } + + if (leaf_MemMgr == NULL) { + leaf_MemMgr = new_MM(sizeof(MLeaf_t)); + } + + if (node_MemMgr == NULL) { + node_MemMgr = new_MM(sizeof(MNode_t)); + } +} + +static MTreeNode_t *allocate_Node(MTree_t *mTree, int height, int base, MTreeNode_t *left, MTreeNode_t *right) { + + // ensure that the allocation structures exist ... + ensureMemMgmt(); + + MNode_t *newNode = allocateObject_MM(node_MemMgr); + + // increment totalNodes + mTree->totalNodes += 1; + + // set internal node attributes + newNode->tag = TAG_MNode_t; + newNode->height = height; + newNode->pivot = calcPivot(height, base); + newNode->base = base; + newNode->digest = NULL; + newNode->left = left; + newNode->right = right; + + // if possible, calc digest for this node + calcDigest(mTree, newNode); + + return (MTreeNode_t *)newNode; +} + +static MTreeNode_t *allocate_Leaf(MTree_t *mTree, int position, Digest_t *digest) { + req_NonNull(digest); + + // ensure that the allocation structures exist ... + ensureMemMgmt(); + + MLeaf_t *newLeaf = allocateObject_MM(leaf_MemMgr); + + // increment totalNodes + mTree->totalNodes += 1; + + // set leaf node attributes + newLeaf->tag = TAG_MLeaf_t; + newLeaf->position = position; + newLeaf->digest = digest; + + return (MTreeNode_t *)newLeaf; +} + +static void deallocate_TreeNode(MTree_t *mTree, void *obj) { + if (obj == NULL) return; + + if (checkTag(obj, TAG_MNode_t)) { + deallocate_Node(mTree, (MNode_t *)obj); + } + else if (checkTag(obj, TAG_MLeaf_t)) { + deallocate_Leaf(mTree, (MLeaf_t *)obj); + } + else { + diagnostic("deallocate_TreeNode: Unrecognised tag value: 0x%u", tagOf(obj)); + codeError_exit(); + } +} + +static void deallocate_Node(MTree_t *mTree, MNode_t *node) { + if (node == NULL) return; + + // ensure that the allocation structures exist ... + ensureMemMgmt(); + + // deallocate the digest + deallocate_DG(node->digest); + + // deallocate left and right nodes (recursive calls) + deallocate_TreeNode(mTree, node->left); + deallocate_TreeNode(mTree, node->right); + + // nullify the attributes of node (except tag) + node->height = 0; + node->pivot = 0; + node->base = 0; + node->digest = NULL; + node->left = NULL; + node->right = NULL; + + // recycle the current tree node + deallocateObject_MM(node_MemMgr, sizeof(MNode_t), node); + + // decrement totalNodes + mTree->totalNodes -= 1; + if (mTree->totalNodes < 0) { + diagnostic("merkleTree.deallocate_Node: Total number of nodes is negative!!"); + codeError_exit(); + } +} + +static void deallocate_Leaf(MTree_t *mTree, MLeaf_t *leaf) { + if (leaf == NULL) return; + + // ensure that the allocation structures exist ... + ensureMemMgmt(); + + // deallocate the digest + deallocate_DG(leaf->digest); + + // nullify the attributes of leaf (except tag) + leaf->position = 0; + leaf->digest = NULL; + + // recycle the current tree node + deallocateObject_MM(leaf_MemMgr, sizeof(MLeaf_t), leaf); + + // decrement totalNodes + mTree->totalNodes -= 1; + if (mTree->totalNodes < 0) { + diagnostic("merkleTree.deallocate_Leaf: Total number of nodes is negative!!"); + codeError_exit(); + } +} + + +// Calculates the pivot value for a given height and base values +static int calcPivot(int height, int base) { + // pivot = base + 2^(height - 1) + return base + pow2(height-1); +} + +// Calculates the height of tree needed to enclose a given position +// - minimum height = 1 +// - maximum height = 31 (!!) +static int calcHeight(int position) { + for (int h = 1; h < 32; h++) { + if (position < pow2(h)) { + return h; + } + } + + return -1; +} + +// gets the height for a non-null tree node +static int getHeightOfNode(MTreeNode_t *node) { + req_NonNull(node); + + switch (tagOf(node)) { + case TAG_MLeaf_t: return 0; + case TAG_MNode_t: return ((MNode_t *)node)->height; + default: + diagnostic("merkleTree.getHeightOfNode: Bad tag value: %i\n", tagOf(node)); + codeError_exit(); + } +} + +// gets the pivot value for a non-null tree node +static int getPivotOfNode(MTreeNode_t *node) { + req_NonNull(node); + + switch (tagOf(node)) { + case TAG_MLeaf_t: return ((MLeaf_t *)node)->position; + case TAG_MNode_t: return ((MNode_t *)node)->pivot; + default: + diagnostic("merkleTree.getPivotOfNode: Bad tag value: %i\n", tagOf(node)); + codeError_exit(); + } +} + + +// sets the left sub-tree and calc digest (if poss.) +static void setLeft(MTree_t *mTree, MNode_t *node, MTreeNode_t *left) { + + req_NonNull(mTree); + req_NonNull(node); + req_NonNull(left); + + if (node->left != NULL) { + diagnostic("merkelTree.setLeft : Left sub-tree is already defined for node."); + error_exit(); + } + // update the left sub-tree + node->left = left; + // if possible, calc digest for this node + calcDigest(mTree, node); +} + + +// sets the right sub-tree and calc digest (if poss.) +static void setRight(MTree_t *mTree, MNode_t *node, MTreeNode_t *right) { + req_NonNull(mTree); + req_NonNull(node); + req_NonNull(right); + + if (node->right != NULL) { + diagnostic("merkelTree.setRight : Right sub-tree is already defined for node."); + error_exit(); + } + // update the right sub-tree + node->right = right; + + // if possible, calc digest for this node + calcDigest(mTree, node); +} + + +// extracts digest if possible - otherwise NULL +static Digest_t *getDigest(MTreeNode_t *item) { + if (item == NULL) return NULL; + + switch (tagOf(item)) { + case TAG_MLeaf_t: return ((MLeaf_t *)item)->digest; + case TAG_MNode_t: return ((MNode_t *)item)->digest; + default: + return NULL; + } +} + +// Calculates digest for tree recursively and updates item +static void calcDigest(MTree_t *mTree, MTreeNode_t *item) { + calcTreeDigest(mTree, item, FALSE); +} + +// Calculates digest for tree recursively and updates item +// - the flag isComplete signals when to complete and perform rightmost promotion +// for any incomplete rightmost subtrees. +static void calcTreeDigest(MTree_t *mTree, MTreeNode_t *item, Boolean_t isComplete) { + if (item == NULL) return; + req_NonNull(mTree); + + if (isLeaf(item)) { + // Leaf nodes always have a digest + return; + } + else if (isNode(item)) { + MNode_t *node = (MNode_t *)item; + + // check if digest already exists + if (node->digest != NULL) return; + + // Try calc. digest if when left and right sub-trees exist. + if (node->left != NULL) { + // Left hand node is non-null + + if (node->right != NULL) { + // if possible, calc digests (recursive step) + calcTreeDigest(mTree, node->left, FALSE); // No promotion step for internal nodes + calcTreeDigest(mTree, node->right, isComplete); + + // extract digests and check if non-NULL + Digest_t *leftDigest = getDigest(node->left); + if (leftDigest == NULL) return; + + Digest_t *rightDigest = getDigest(node->right); + if (rightDigest == NULL) return; + + // Both digests exist ... so now build digest object + HashSpec_t hSpec = getHashSpec_DG(leftDigest); + Digest_t *nodeDigest = new_DG(hSpec); + + // set up temp bytevector + ByteVec_t *tempBV = new_BV(); + // Load up temp bytevector + getHashValue_DG(leftDigest, tempBV); // Add in left bytevector + + getHashValue_DG(rightDigest, tempBV); // Add in right bytevector + + // Hash the contents of tempBV + hashBV_DG(nodeDigest, tempBV); + + // Link new digest to node + node->digest = nodeDigest; + + // recycle temp bytevector + deallocate_BV(tempBV); + // If autoClean is set, deallocate nodes + if (mTree->autoClean) { + deallocate_TreeNode(mTree, node->left); + deallocate_TreeNode(mTree, node->right); + } + } + else if (isComplete) { + rightmostPromotion(mTree, node); + } + } + } +} + + +// Rightmost Promotion step. +// This "rightmost promotion step" is needed when the binary tree is not completely filled +// e.g. the number of total positions filled isn't the maximum possible. +// In that case there will be some rightmost subtrees with NULL right subtrees, +// which are not going to be filled i.e. acquire a digest. +// +// Thus, promotion only used on the rightmost nodes which have NULL right nodes. +// Thus, never used "internally" to tree. +// +// Promotion then takes the non-NULL left most elements and uses +// those hashes in the nodes above. +static void rightmostPromotion(MTree_t *mTree, MNode_t *node) { + req_NonNull(mTree); + req_NonNull(node); + + // recursive step ... + calcTreeDigest(mTree, node->left, TRUE); + + // Fetch the leftDigest + Digest_t *leftDigest = getDigest(node->left); + + // Check that the digest is defined ... + if (leftDigest != NULL) { + HashSpec_t hSpec = getHashSpec_DG(leftDigest); + Digest_t *nodeDigest = new_DG(hSpec); + + if (!clone_DG(nodeDigest, leftDigest)) { + diagnostic("merkleTree.rightmostPromotion : Failed to clone digest"); + codeError_exit(); + } + + // copy cloned digest ... + node->digest = nodeDigest; + } +} + + +// Inflate tree to correct height, as needed. +static void inflateTree(MTree_t *mTree, int nodeHeight) { + + req_NonNull(mTree); + req_PosZero(nodeHeight); + + if (nodeHeight <= mTree->height) return; + + // update the mTree's height ... + mTree->height = nodeHeight; + + // need to inflate tree ... + if (mTree->treeRoot == NULL) { + // set new root of correct height + mTree->treeRoot = allocate_Node(mTree, nodeHeight, 0, NULL, NULL); + } + else { + // capture old root + MTreeNode_t *oldRoot = mTree->treeRoot; + + // set new root of correct height + mTree->treeRoot = allocate_Node(mTree, nodeHeight, 0, NULL, NULL); + + //insert old root back into tree ... + insertNode(mTree, mTree->treeRoot, oldRoot); + } +} + +// recursive insertion of a node into tree +static void insertNode(MTree_t *mTree, MTreeNode_t *treeNode, MTreeNode_t *newTreeNode) { + + req_NonNull(mTree); + req_NonNull(treeNode); + req_NonNull(newTreeNode); + + // check tags ... + switch (tagOf(treeNode)) { + case TAG_MLeaf_t: + diagnostic("merkleTree.insertNode : Current node is a leaf - can't insert anything into a leaf"); + codeError_exit(); + + case TAG_MNode_t: + break; + + default: + diagnostic("merkleTree.insertNode: Bad tag value: 0x%x\n", (Byte_t)tagOf(treeNode)); + codeError_exit(); + } + + MNode_t *curNode = (MNode_t *)treeNode; + int curHeight = curNode->height; + int curPivot = curNode->pivot; + + int nodeHeight = getHeightOfNode(newTreeNode); + int nodePivot = getPivotOfNode(newTreeNode); + + // sanity checks ... + if (curHeight <= 0) { + diagnostic("merkleTree.insertNode : Current height (%i) of node is not positive", curHeight); + codeError_exit(); + } + + if (curHeight < nodeHeight) { + diagnostic("merkleTree.insertNode : Height of current node (%i) < height of new node (%i)", curHeight, nodeHeight); + codeError_exit(); + } + + if (curHeight-1 == nodeHeight) { + // insert newTreeNode as direct subtree of curNode + // - this must be currently NULL + if (nodePivot < curPivot) { + setLeft(mTree, curNode, newTreeNode); + } + else { + setRight(mTree, curNode, newTreeNode); + } + } + else { + // Need to insert newTreeNode further down ... + if (nodePivot < curPivot) { + // insert into left sub tree + MTreeNode_t *leftNode = curNode->left; + if (leftNode == NULL) { + int leftBase = curNode->base; + leftNode = allocate_Node(mTree, curHeight-1, leftBase, NULL, NULL); + + // attach new left node to current node + setLeft(mTree, curNode, leftNode); + } + + // recursive call to insertNode + insertNode(mTree, leftNode, newTreeNode); + } + else { + // insert into right sub tree + MTreeNode_t *rightNode = curNode->right; + if (rightNode == NULL) { + int rightBase = curPivot; + rightNode = allocate_Node(mTree, curHeight-1, rightBase, NULL, NULL); + + // attach new right node to current node + setRight(mTree, curNode, rightNode); + } + + // recursive call to insertNode + insertNode(mTree, rightNode, newTreeNode); + } + } +} + +// Useful basic displayer of nodes ... +static StringBuf_t *displaySB = NULL; +static int fpLength = 8; +char *displayNode(MTreeNode_t *item) { + if (item == NULL) return NULL_STR; + + if (displaySB == NULL) { + displaySB = new_SB(); + } + else { + reset_SB(displaySB); + } + + if (isNode(item)) { + MNode_t *node = (MNode_t *)item; + + int height = node->height; + int pivot = node->pivot; + int base = node->base; + char *digestStr = showFingerprint_DG(node->digest, fpLength); + + addItems_SB(displaySB, "Node <id=0x%lx, height=%i, pivot=%i, base=%i, digest=%s>" + , (unsigned long)node + , height + , pivot + , base + , digestStr + ); + } + else if (isLeaf(item)) { + MLeaf_t *leaf = (MLeaf_t *)item; + int position = leaf->position; + char *digestStr = showFingerprint_DG(leaf->digest, fpLength); + + addItems_SB(displaySB, "Leaf <id=0x%lx, position=%i, digest=%s>" + , (unsigned long)leaf + , position + , digestStr + ); + } + else { + diagnostic("displayNode : Unknown tag for object: 0x%x", (Byte_t)tagOf(item)); + codeError_exit(); + } + + return (char *)getContent_BV(displaySB); +} + + +/******************************************************************************* + Showing Hash Trees +*******************************************************************************/ +static void initShowTree(StringBuf_t *sbuf); +static void showTree(MTree_t *mTree); +static void resetShowTree(); + +static void setCurIndent(int indentLevel); +static void showTreeNode(MTreeNode_t *node, int indentLevel); +static void showNode(MNode_t *node, int indentLevel); +static void showLeaf(MLeaf_t *node, int indentLevel); + +static StringBuf_t *curSBuf = NULL; +static int maxLevel = 0; +static char *curIndent = NULL; +static int totalIndentLength = 0; +static int curIndentLevel = 0; + +static int indentLen = 0; +static int incrIndentLen = 0; + +static void setCurIndent(int indentLevel) { + // ensure initialisation + if (curIndent == NULL) { + totalIndentLength = LINE_BUFSIZE+1; + curIndent = ALLOC_ARR(totalIndentLength, char); + + // initialising curIndent etc. ... + indentLen = strlen(show_indent); + incrIndentLen = strlen(show_incrIndent); + + memcpy(curIndent, show_indent, indentLen); + } + + int curLength = strlen(curIndent); + int diffIndent = indentLevel - curIndentLevel; + + // set the current indent level + curIndentLevel = indentLevel; + + // check if there is a difference in indent ... + if (diffIndent == 0) { + return; + } + else if (diffIndent < 0) { + int offset = diffIndent * incrIndentLen; + curLength += offset; + + if (curLength < indentLen) { + diagnostic("merkleTree.setCurIndent: Bad indent level: %i", indentLevel); + codeError_exit() + } + + // update curIndent + curIndent[curLength] = 0; + + return; + } + else { + int posn = curLength; + + for (int i = 0; i < diffIndent; i++) { + memcpy(curIndent + posn, show_incrIndent, incrIndentLen); + posn += incrIndentLen; + } + } +} + + +static void showTreeNode(MTreeNode_t *node, int indentLevel) { + if (node == NULL) { + setCurIndent(curIndentLevel); + addItems_SB(curSBuf, "%s<NULL TREE NODE>\n", curIndent); + } + + switch (tagOf(node)) { + case TAG_MLeaf_t: showLeaf((MLeaf_t *)node, indentLevel); + case TAG_MNode_t: showNode((MNode_t *)node, indentLevel); + default: + diagnostic("merkleTree.showTreeNode: Bad tag value: %i\n", tagOf(node)); + codeError_exit(); + } +} + +static void showNode(MNode_t *node, int indentLevel) { + setCurIndent(indentLevel); + + // check if indentLevel exceed maxLevel + if (indentLevel > maxLevel) { + addItems_SB(curSBuf, "%s...\n", curIndent); + } + + addItems_SB(curSBuf, "%sHeight: %i\n", curIndent, node->height); + addItems_SB(curSBuf, "%sPivot: %i\n", curIndent, node->pivot); + addItems_SB(curSBuf, "%sBase: %i\n", curIndent, node->base); + addItems_SB(curSBuf, "%sDigest: 0x%s\n", curIndent, showFingerprint_DG(node->digest, fpLength)); + + showTreeNode(node->left, indentLevel+1); + + showTreeNode(node->right, indentLevel+1); +} + +static void showLeaf(MLeaf_t *leaf, int indentLevel) { + setCurIndent(indentLevel); + + // check if indentLevel exceed maxLevel + if (indentLevel > maxLevel) { + addItems_SB(curSBuf, "%s...\n", curIndent); + } + + addItems_SB(curSBuf, "%sHeight: 0\n", curIndent); + addItems_SB(curSBuf, "%sDigest: 0x%s\n", curIndent, showFingerprint_DG(leaf->digest, fpLength)); +} + +static void initShowTree(StringBuf_t *sbuf) { + resetShowTree(); + + curSBuf = sbuf; +} + +static void showTree(MTree_t *mTree) { + req_NonNull(mTree); + + // recompute maxLevel + maxLevel = show_max_depth; + if (maxLevel <= 0) { + maxLevel = min(mTree->height + 1, MAX_TREE_HEIGHT); + } + + setCurIndent(0); + addItems_SB(curSBuf, "%sMTree <state:%s, height:%i, blockCount:%i, maxPosition:%i, digest:0x%s>\n" + , curIndent + , showState_MT(mTree) + , mTree->height + , mTree->blockCount + , mTree->maxPosition + , showFingerprint_DG(mTree->topHash, fpLength) + ); + + // show the full tree if not compact ... + if (!show_compact_display) { + showTreeNode(mTree->treeRoot, 0); + } +} + +static void resetShowTree() { + // deallocate curIndent + free(curIndent); + + // set the curIndent to NULL to avoid double freeing ... + curIndent = NULL; +} + + +/******************************************************************************* + + +// local debugging function ... +// - allows local tests to be exported to a wider context +void localTest(); + +//////////////////////////////////////////////////////////////////////////////// +// Test 2 +void localTest () { + debugOn = FALSE; + + HashSpec_t hSpec = HSP_SHA256; + + Digest_t *digest0 = new_DG(hSpec); + Digest_t *digest1 = new_DG(hSpec); + + MTree_t *mTree = new_MT(hSpec); + + MNode_t *node = allocate_Node(mTree, 1, 0, NULL, NULL); + + MLeaf_t *leaf0 = allocate_Leaf(mTree, 0, digest0); + MLeaf_t *leaf1 = allocate_Leaf(mTree, 1, digest1); + + printf("Node = %s\n", displayNode(node)); + printf("Leaf0 = %s\n", displayNode(leaf0)); + printf("Leaf1 = %s\n", displayNode(leaf1)); + + printf("\n\nSetting right ...\n"); + setRight(node, leaf1); + + printf("\n\nSetting left ...\n"); + setLeft(node, leaf0); + + printf("\n\nReprinting ...\n"); + printf("Node = %s\n", displayNode(node)); + printf("Leaf0 = %s\n", displayNode(leaf0)); + printf("Leaf1 = %s\n", displayNode(leaf1)); + +} + + +//////////////////////////////////////////////////////////////////////////////// +// Test1 +void localTest () { + HashSpec_t hSpec = HSP_SHA256; + + MTree_t *mTree = new_MT(hSpec); + + MNode_t *node = allocate_Node(mTree, 1, 0, NULL, NULL); + + printf("tag of node = %c isNode = %s\n", tagOf(node), showBoolean(isNode(node))); + + printf("Node = %s\n", displayNode(node)); +} + +*/ diff --git a/hash_fusion/lib/merkleTree.h b/hash_fusion/lib/merkleTree.h new file mode 100644 index 0000000000..81a9b8a3f1 --- /dev/null +++ b/hash_fusion/lib/merkleTree.h @@ -0,0 +1,135 @@ +#ifndef __MERKLE_TREE_H__ +#define __MERKLE_TREE_H__ + +/******************************************************************************* + merkleTree.h + + Merkle Tree + - Standard Peer-2-Peer hashing of a sequence of blocks + - Handles building of data sequence in random order ... + - Merkle, R. C. (1988). "A Digital Signature Based on a Conventional Encryption Function". + Advances in Cryptology — CRYPTO '87. Lecture Notes in Computer Science 293. p. 369 + + Author: brian.monahan@hpe.com + + (c) Copyright 2017 Hewlett Packard Enterprise Development LP + + 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. + + 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. +*******************************************************************************/ + +#include "utils.h" +#include "bytevector.h" +#include "stringbuffer.h" +#include "hashlib.h" + +// Sequential blocks +typedef struct merkleTree MTree_t; + +// Merkle Tree state +// - Merkle tree operations cycle: init->partial->complete->final +typedef int MTreeState_t; + +// Merkle Tree state +// - a complete sequence means there are no missing blocks (i.e. no gaps between 0 and current max position). +// - even if we have a complete sequence, there could still be more input. +#define MTree_NULL 0 // Not a valid state (i.e. uninitialised) +#define MTree_Initial 1 // Initial state (empty sequence) +#define MTree_Partial 2 // Partial state (partial sequence) - in progress/under construction +#define MTree_Complete 3 // Complete state (completed initial sequence, but there could be more input ...) +#define MTree_Final 4 // Final state (completed sequence, and no more blocks to be added) + +// The default auto clean option +// - If set autoClean TRUE, deallocate tree nodes as soon as possible. +Boolean_t autoCleanDefault; + +// New Merkle Tree +// - initialises the tree object +// - Auto clean is set to the default as defined by autoCleanDefault. +MTree_t *new_MT(HashSpec_t hSpec); + +// Allocates Merkle Tree +// - initialises the tree object +// - The autoClean setting can be defined. +MTree_t *allocate_MT(HashSpec_t hSpec, Boolean_t autoClean); + +// Deallocate/recycle Merkle Tree object +void deallocate_MT(MTree_t *mTree); + +// Resets the given hash tree +// - The existing autoClean state from mTree is reused. +void reset_MT(MTree_t *mTree, HashSpec_t hSpec); + +// Inspect current state ... +MTreeState_t getState_MT(MTree_t *mTree); + +// Show current state ... +char *showState_MT(MTree_t *mTree); + +// Gets current Hash Spec +HashSpec_t getHashSpec_MT(MTree_t *mTree); + +// Gets Top Hash - if defined +// - This clones the mTree's digest object into given digest, dgst. +// - Returns TRUE only if digest was cloned. +Boolean_t getTopHash_MT(Digest_t *dgst, MTree_t *mTree); + +// Gets the total number of blocks so far. +int getNumBlocks_MT(MTree_t *mTree); + +// Gets the total number of tree nodes (i.e. internal nodes and leaves). +int getTotalNodes_MT(MTree_t *mTree); + +// Gets the auto clean flag. +// - if TRUE, deallocate tree nodes as soon as possible. +Boolean_t getAutoClean_MT(MTree_t *mTree); + +// Gets the height of the hash tree ... +int getHeight_MT(MTree_t *mTree); + +// Show hash tree by appending to stringbuffer +// - set indent string +// - set incrment indent string +// - set compact display +// - set max depth (if positive) +void show_MT(MTree_t *mTree, StringBuf_t *sbuf); +void setShowIndent_MT(char * indent); +void setShowIncrIndent_MT(char * indent); +void setShowCompact_MT(Boolean_t isCompact); +void setShowMaxDepth_MT(int maxDepth); + +// Adds data block into sequence +// - position is 1-based i.e. from 1 to N +void addDataBlock_MT(MTree_t *mTree, int position, ByteVec_t *dataVec); + +// Finalise the tree (if possible) +// - Returns true if successfully finalised, otherwise false. +Boolean_t finalise_MT(MTree_t *mTree); + +// Maximum indent length +#define MAX_INDENT_LENGTH 20 + +// Maximum Tree Height ... +#define MAX_TREE_HEIGHT 32 + +#endif diff --git a/hash_fusion/lib/options.h b/hash_fusion/lib/options.h new file mode 100644 index 0000000000..95749c645c --- /dev/null +++ b/hash_fusion/lib/options.h @@ -0,0 +1,43 @@ +#ifndef __OPTIONS_H__ +#define __OPTIONS_H__ + +/******************************************************************************* + options.h + + Application options + + Author: brian.monahan@hpe.com + + (c) Copyright 2017 Hewlett Packard Enterprise Development LP + + 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. + + 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 __FAST_MULTIPLY__ option enable fast matrix multiplication +// algorithms (for triangular matrices). +#define __FAST_MULTIPLY__ TRUE +//#define __FAST_MULTIPLY__ FALSE + + +#endif diff --git a/hash_fusion/lib/position.h b/hash_fusion/lib/position.h new file mode 100644 index 0000000000..07cdfd3245 --- /dev/null +++ b/hash_fusion/lib/position.h @@ -0,0 +1,39 @@ +#ifndef __POSITION_H__ +#define __POSITION_H__ + +/******************************************************************************* + position.h + + Author: brian.monahan@hpe.com + + (c) Copyright 2017 Hewlett Packard Enterprise Development LP + + 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. + + 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. + +*******************************************************************************/ + +#include "utils.h" // Standard utils + + +#endif diff --git a/hash_fusion/lib/random.c b/hash_fusion/lib/random.c new file mode 100644 index 0000000000..0bcad7a0e6 --- /dev/null +++ b/hash_fusion/lib/random.c @@ -0,0 +1,141 @@ +/* random.c + + Basic randomisation ... + + Uses simple Park-Miller MINSTD Lehmer RNG ... + + Author: brian.monahan@hpe.com + + (c) Copyright 2017 Hewlett Packard Enterprise Development LP + + 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. + + 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. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <math.h> + +#include "utils.h" +#include "random.h" + + +unsigned long curState = -1; + +unsigned long m = 2147483647; // 2^31 - 1 +unsigned long a = 16807; // 7^5 + +// params +int getModulus() { return (int)m; } +int getMultiplier() { return (int)a; } + + +// Gets the current seed +unsigned int getSeed() { + return curState; +} + + +// sets seed +// - selects randomised value, by giving a 0 seed value ... +void setSeed(unsigned int seed) { + if (seed == 0) { + seed = (unsigned int)time(NULL); + } + + curState = seed % m; +} + +// choose next random value +unsigned int nextRandom() { + curState = (a*curState % m); // Needs long (64-bit) to avoid overflow ... + return (unsigned int)curState; +} + + +// choose next random Boolean value +Boolean_t nextRandom_Boolean() { + return (nextRandom() % 2 == 0 ? TRUE : FALSE); +} + + +// choose next Boolean event according to probability +// - Value is TRUE on probability: pro / (pro + con) +// - Value is FALSE on probability: con / (pro + con) +Boolean_t nextRandom_Event(double pro, double con) { + double prob = pro / (pro + con); + return (nextRandom_Real() < prob ? TRUE : FALSE); +} + + +// choose random value v in **closed interval range**, where a <= v <= b. +int nextRandom_Range(int a, int b) { + if (a == b) return a; + + if (a > b) { + int c = a; + a = b; + b = c; + } + + int mod = (b - a) + 1; + unsigned int val = nextRandom() % mod; + return val + a; +} + + +// choose next random Byte_t value +Byte_t nextRandom_BYTE() { + return (Byte_t)nextRandom(); +} + + +// choose a random value in the range (0, 1) +double nextRandom_Real() { + //double val = (double)nextRandom(); + return (double)nextRandom()/m; +} + + +/* +void test() { + unsigned int val = 0; + int count = 0; + + printf("a = %i\n", a); + printf("m = %i\n", m); + + //if x0 = 1, then x10000 = 1043618065 + setSeed(1); + + for (int i = 0; i <= 10003; i++) { + val = nextRandom(); + count = i % 1000; + if (count < 3 || 1000-3 < count) { + printf("%i. val = %u = %.9g\n", i, val, (double)val/m); + } + } +} +*/ diff --git a/hash_fusion/lib/random.h b/hash_fusion/lib/random.h new file mode 100644 index 0000000000..1674c84ef8 --- /dev/null +++ b/hash_fusion/lib/random.h @@ -0,0 +1,80 @@ +#ifndef __RANDOM_H__ +#define __RANDOM_H__ + + +#include "utils.h" + +/******************************************************************************* + random.h + + Simple random number generators + - Uses the Park-Miller MINSTD Lehmer generator: + + a = 7^5 = 16807 + m = 2^31 - 1 = 2147483647 + + x_n+1 = (a * x_n) mod m + + See: Park and Miller, "Random Number Generators: Good ones are hard to find", + Communications of the ACM, October 1988, Volume 31, No 10, pages 1192-1201. + + Author: brian.monahan@hpe.com + + (c) Copyright 2017 Hewlett Packard Enterprise Development LP + + 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. + + 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. +*******************************************************************************/ + +// params +//int getModulus(); +//int getMultiplier(); + +// Gets the current seed +unsigned int getSeed(); + +// Sets seed +// - selects randomised value, by giving a 0 seed value ... +void setSeed(unsigned int seed); + +// choose next random integer value +unsigned int nextRandom(); + +// choose next random Boolean value (fair) +Boolean_t nextRandom_Boolean(); + +// choose next Boolean event according to probability +// - Value is TRUE on probability: pro / (pro + con) +// - Value is FALSE on probability: con / (pro + con) +Boolean_t nextRandom_Event(double pro, double con); + +// choose random value v in **closed interval range**, where a <= v <= b. +int nextRandom_Range(int a, int b); + +// choose next random Byte_t value +Byte_t nextRandom_BYTE(); + +// choose a random value in the range (0, 1) +double nextRandom_Real(); + +#endif diff --git a/hash_fusion/lib/rbTree.c b/hash_fusion/lib/rbTree.c new file mode 100644 index 0000000000..b909b3c231 --- /dev/null +++ b/hash_fusion/lib/rbTree.c @@ -0,0 +1,2185 @@ +/******************************************************************************* + rbTree.c + + Red-Black Trees + + - Implements ordered keys mapping to value (i.e. ordered treemap). + + Provides set and/or map abstractions. + + - Significant input from: + + Chapter 12, Binary Search Trees + + Chapter 13, Red-Black Trees + + from Cormen et al, Introduction to Algorithms, 3rd Ed. MIT Press + + Keys are encoded as an "opaque" type (see utils.h) + + Red-Black properties: + ===================== + - Each internal node has colour either RED or BLACK. + + - The root of the tree is BLACK. + + - If a node is RED, then both of its decendants must be BLACK. + + - All terminal nodes (i.e. NULLs) are BLACK. + + - All new nodes start out being coloured RED. + + - For every node, the total number of BLACK nodes is the same for each + decendant path from the node to the leaves. + + Author: brian.monahan@hpe.com + + (c) Copyright 2017 Hewlett Packard Enterprise Development LP + + 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. + + 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. +*******************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include "utils.h" +#include "stringbuffer.h" +#include "alloc.h" +#include "rbTree.h" + + +// Colour data type +typedef enum { BLACK, RED } Colour_t; + +// This encodes the internal red-black tree node. +// The tree components left and right may be LEAF (i.e. terminal leaf nodes). +// The only tree having LEAF parent is a root ... + +typedef struct rbTreeNode Node_t; + +struct rbTreeNode { + Node_t *left; + Node_t *right; + Node_t *parent; // This pointer could always be computed ... it is convenient to compute it + + unsigned int id; // unique id for the node - this is never recycled. + + Colour_t colour; // This could be encoded into the last bit of a pointer. + + Key_t key; // NULL_KEY represents "default" key + void *data; // data pointer ... + + // synthetic attributes - these are convenient (but unnecessary) + Boolean_t needUpd; // TRUE when synthetic attributes need updating + + int size; // number of nodes in this subtree (inclusive) + Byte_t height; // height of subtree (inclusive) + Byte_t bHeight; // black height for subtree (not incl. this node). +}; + + +// Red-Black Tree structure +// - This encodes the root of the tree itself. +struct rbTree { + VoidFn_t finalObjFn; + CompareFn_t keyCompFn; + + Boolean_t cacheOn; + Key_t cachedKey; // Could be either NULL or non-NULL + void *cachedData; + + Boolean_t allowUpd; // TRUE when insert may update existing entries. + Boolean_t allowNullKey; // TRUE when NULL_KEY is allowed as a valid key. + + Node_t *root; +}; + + +// Default flag value for allowing updates within the tree. +#define DEFAULT_ALLOW_UPDATES TRUE + + +// Default flag value for allowing NULL_KEY as a valid key. +#define DEFAULT_ALLOW_NULL_KEY TRUE +; + + +/******************************************************************************* + Memory Management +*******************************************************************************/ +static MemMgr_t *rbTree_MemMgr = NULL; +static MemMgr_t *rbNode_MemMgr = NULL; + + +/******************************************************************************* + Node IDs +*******************************************************************************/ +static unsigned int nextNodeID = 1; + + +/******************************************************************************* + LEAF node object + - This is the unique terminating node object. +*******************************************************************************/ +static Node_t *LEAF = NULL; + +static void setupLeafObject() { + if (LEAF != NULL) return; + + // Allocate memory for this object + LEAF = ALLOC_OBJ(Node_t); + + // Set attributes + LEAF->left = LEAF; + LEAF->right = LEAF; + LEAF->parent = LEAF; + + LEAF->id = 0; + + LEAF->key = NULL_KEY; + LEAF->data = NULL; + + // Synthetic attributes + LEAF->needUpd = FALSE; + LEAF->size = 0; + LEAF->height = 0; + LEAF->bHeight = 0; +} + + +/******************************************************************************* + Static method prototypes +*******************************************************************************/ + +// Insertion helpers +static void *insertNode(RBTree_t *tree, Key_t key, void *val); +static void fixupInsert(RBTree_t *tree, Node_t *newNode); + +// Deletion helpers +static void removeInfo(RBTree_t *tree, Node_t * targetNode); +static void fixupDelete(RBTree_t *tree, Node_t *fixupNode); + +// Memory management helpers +static void ensureMemMgmt(); + +static Node_t *allocate_Node(Key_t key, void *data); +static void deallocate_Node(RBTree_t *tree, Node_t *node); +static void deallocate_All(RBTree_t *tree, Node_t *node, VoidFn_t finalObjFn); + +// Node ID +static int nodeID(Node_t *node); +static char *showNodeID(Node_t *node); + +// Comparing opaque keys +static Comparison_t cmpKey(RBTree_t *tree, Key_t keyA, Key_t keyB); + +static Boolean_t keyLT(RBTree_t *tree, Key_t keyA, Key_t keyB); +static Boolean_t keyEQ(RBTree_t *tree, Key_t keyA, Key_t keyB); +static Boolean_t keyGT(RBTree_t *tree, Key_t keyA, Key_t keyB); + +// Showing keys +static char *showKey(Key_t key); + +// Accessing extended attributes (e.g. height) +static int nodeNumNodes(Node_t *node); +static int nodeHeight(Node_t *node); +static int nodeBHeight(Node_t *node); + +// Total bHeight = bHeight + colour weighting ... +static int totalBHeight(Node_t *node); + +// Getting colours +static Colour_t nodeColour(Node_t *node); + +static Boolean_t nodeIsBlack(Node_t *node); +static Boolean_t nodeIsRed(Node_t *node); + +// Showing colours +static char *showColour(Colour_t colour); +static char *showNodeColour(Node_t *node); + +// Checking for leaf/null nodes +static Boolean_t nodeIsLeaf(Node_t *node); +static Boolean_t nodeIsProper(Node_t *node); + +// checking blackHeight balance +static Boolean_t nodeIsBalanced(Node_t *node); + +// extracting nodes +static Node_t *nodeLeft(Node_t *node); +static Node_t *nodeRight(Node_t *node); +static Node_t *nodeParent(Node_t *node); + +// finding nodes +static Node_t *findNode(RBTree_t *tree, Key_t key); + +static Node_t *matchFirstNode(Node_t *curNode, PredFn_t predFn); +static Node_t *matchLastNode(Node_t *curNode, PredFn_t predFn); + +static Node_t *findNextNode(RBTree_t *tree, Key_t key, Boolean_t allowEQ); +static Node_t *findPrevNode(RBTree_t *tree, Key_t key, Boolean_t allowEQ); + +static Node_t *findMinForTree(RBTree_t *tree); +static Node_t *findMaxForTree(RBTree_t *tree); + +static Node_t *getPreviousNode(Node_t *node); +static Node_t *getSuccessorNode(Node_t *node); + +static Node_t *getLeftmostNode(Node_t *node); +static Node_t *getRightmostNode(Node_t *node); + +// caching info ... +static Key_t setCacheInfo_Key(RBTree_t *tree, Node_t *result); +static void *setCacheInfo_Data(RBTree_t *tree, Node_t *node); + +// checking tree +static Boolean_t check_treenode(Node_t *node); +static Boolean_t check_subnode_parents(Node_t *node); +static Boolean_t check_RB_properties(Node_t *node); + +// showing tree +static void initShowTree(StringBuf_t *sbuf); +static void showTree(RBTree_t *mTree); + +// showing pointers +static Ptr_t convPtr(void *addr); + +// updating extended attributes (height etc.) +static void updateAttrs_Tree(RBTree_t *tree); +static void updateAttrs_All(Node_t *node); // This checks the update status +static void forcedUpdateAttrs(Node_t *node); // This updates always +static Boolean_t updateAttrs_Node(Node_t *node); +//static void updateAttrs_Parent(Node_t *node); + +static void markUpdateNeeded(Node_t *node); + +// Rotation of nodes +static void leftRotate(RBTree_t *tree, Node_t *node); +static void rightRotate(RBTree_t *tree, Node_t *node); + + +/******************************************************************************* + Parameters + - These parameters are typically varied for testing purposes. + - As they affect all instances, they should not be relied upon in production. +*******************************************************************************/ +// Enable/disable internal checking of RB tree +Boolean_t doInternalChecks = FALSE; + +// Enable/disable output of reports from checking: +Boolean_t outputCheckReports = TRUE; + +// Enable balancing +Boolean_t doBalancing = TRUE; + +// Abort when checking the tree fails +Boolean_t abortOnCheckFailure = TRUE; + + +/******************************************************************************* + Methods +*******************************************************************************/ +// Allocate an RBTree_t object ... +// - finalObjFn - Used to deallocate data objects when disposing +// - If function is NULL, then nothing is done. +// +// - keyCompFn - Used to compare non-NULL keys - as a linear (less-than) ordering. +// - This function does not need to consider NULL_KEYs as input. +// - If function is NULL, then the standard < ordering on unsigned long values is used. +RBTree_t *new_RBT(CompareFn_t keyCompFn) { + // ensure that the allocation structures exist ... + ensureMemMgmt(); + + // determine default functions ... + keyCompFn = (keyCompFn == NULL ? cmp_key : keyCompFn); + + // allocate new Tree + RBTree_t *newTree = allocateObject_MM(rbTree_MemMgr); + + // set attributes + newTree->finalObjFn = nullVoidFn; + newTree->keyCompFn = keyCompFn; + + newTree->cacheOn = FALSE; + newTree->cachedKey = NULL_KEY; + newTree->cachedData = NULL; + newTree->allowUpd = DEFAULT_ALLOW_UPDATES; + newTree->allowNullKey = DEFAULT_ALLOW_NULL_KEY; + newTree->root = LEAF; + + return newTree; +} + +// Deallocate an RBTree object ... +void deallocate_RBT(void *item) { + if (item == NULL) return; + + RBTree_t *tree = (RBTree_t *)item; + + // ensure that the allocation structures exist ... + ensureMemMgmt(); + + // Deallocate all from root + deallocate_All(tree, tree->root, tree->finalObjFn); + + // nullify the attributes of tree + NULLIFY_OBJ(tree, RBTree_t) + + // recycle the current tree object + deallocateObject_MM(rbTree_MemMgr, sizeof(RBTree_t), tree); +} + + +// Deallocate an RBTree object ... with specific object finaliser +void deallocateWithFinaliser_RBT(void *item, VoidFn_t finalObjFn) { + if (item == NULL) return; + + RBTree_t *tree = (RBTree_t *)item; + + // ensure that the allocation structures exist ... + ensureMemMgmt(); + + // Deallocate all from root + deallocate_All(tree, tree->root, finalObjFn); + + // nullify the attributes of tree + NULLIFY_OBJ(tree, RBTree_t) + + // recycle the current tree object + deallocateObject_MM(rbTree_MemMgr, sizeof(RBTree_t), tree); +} + + +// Set object finaliser function ... +// - No finalisation happens for data items unless this is set. +void setFinaliser_RBT(RBTree_t *tree, VoidFn_t finalObjFn) { + req_NonNull(tree); + + // normalising function to be non-null + finalObjFn = (finalObjFn == NULL ? nullVoidFn : finalObjFn); + + tree->finalObjFn = finalObjFn; +} + + +// Inserts data under given key into given tree ... +// - If key already exists in tree: +// + replaces previous data with dataItem. +// + return previous data. +// - Otherwise, insert new dataItem and return NULL. +void *insert_RBT(RBTree_t *tree, Key_t key, void *dataItem) { + req_NonNull(tree); + + // Check if NULL_KEY is permitted + if (!tree->allowNullKey && key == NULL_KEY) { + return NULL; + } + + // update the cache, if necessary + if (tree->cacheOn && keyEQ(tree, key, tree->cachedKey)) { + tree->cachedData = dataItem; + } + + // Add to key/data to tree + // - Capture any previously held data + void *prevData = insertNode(tree, key, dataItem); + + // Perform the finaliser on prevData + // - This function may do nothing on prevData ... + // - Thus, the data pointer prevData is returned in any case. + tree->finalObjFn(prevData); + + // Perform update of attributes from root (as necessary) + updateAttrs_Tree(tree); + + // Perform checks when balancing + if (doInternalChecks && doBalancing) { + checkTree_RBT(tree); + } + + // Return old data pointer ... + return prevData; +} + +// Deletes data under given key from given tree. +// - If found, returns the data pointer found. +// - Otherwise return NULL +void *delete_RBT(RBTree_t *tree, Key_t key) { + req_NonNull(tree); + + // Check if NULL_KEY is permitted + if (!tree->allowNullKey && key == NULL_KEY) { + return NULL; + } + + // Clear the cache, if necessary + if (tree->cacheOn && keyEQ(tree, key, tree->cachedKey)) { + tree->cachedKey = NULL_KEY; + tree->cachedData = NULL; + tree->cacheOn = FALSE; + } + + // Find the node to be deleted + Node_t *delNode = findNode(tree, key); + + // check if deleted node was found + if (nodeIsLeaf(delNode)) { + + return NULL; + } + + // Capture data pointer from the node to be deleted + void *prevData = delNode->data; + + // Now remove the information ... + // - In fact, the tree is rearranged so that the information is removed. + // - Node id's at which information is found may change. + // - The number of nodes is decreased by 1 ... + removeInfo(tree, delNode); + + // Perform the finaliser on prevData + // - This function may do nothing on prevData ... + // - Thus, the data pointer prevData is returned in any case. + tree->finalObjFn(prevData); + + // perform update of attributes from root (as necessary) + updateAttrs_Tree(tree); + + // Perform checks when balancing + if (doInternalChecks && doBalancing) { + checkTree_RBT(tree); + } + + // Return old data pointer ... + return prevData; +} + + +// Checks that key belongs to given tree - as a domain element. +// - Successful lookups are cached. +Boolean_t member_RBT(RBTree_t *tree, Key_t key) { + req_NonNull(tree); + + // When NULL_KEY is not permitted, return FALSE for key == NULL_KEY + if (!tree->allowNullKey && key == NULL_KEY) { + return FALSE; + } + + // check if key was cached ... + // if yes, then key is present in the tree ... + if (tree->cacheOn && keyEQ(tree, key, tree->cachedKey)) return TRUE; + + Node_t *curNode = findNode(tree, key); + + // cache result of search + setCacheInfo_Data(tree, curNode); + + // returns TRUE if proper node was found ... + return (nodeIsProper(curNode)); +} + +// Lookup data in tree for the given key +// - If found, returns the corresponding data pointer for the given key. +// - Otherwise return NULL +// - Successful lookups are cached. +// (Unsuccessful lookups clear the cache) +void *lookup_RBT(RBTree_t *tree, Key_t key) { + req_NonNull(tree); + + // When NULL_KEY is not permitted, return NULL for key == NULL_KEY + if (!tree->allowNullKey && key == NULL_KEY) { + return NULL; + } + + // check if key was cached ... + if (tree->cacheOn && keyEQ(tree, key, tree->cachedKey)) return tree->cachedData; + + Node_t *curNode = findNode(tree, key); + + // cache result of search + return setCacheInfo_Data(tree, curNode); +} + + +// find key of first element matching the predicate ... +// - finds the key of the first/least element in the tree satisfying the predicate +Key_t findFirstMatch_RBT(RBTree_t *tree, PredFn_t predFn) { + req_NonNull(tree); + + Node_t *curNode = matchFirstNode(tree->root, predFn); + + // cache result of search + return setCacheInfo_Key(tree, curNode); +} + + +// find key of last element matching the predicate ... +// - finds the key of the last/greatest element in the tree satisfying the predicate +Key_t findLastMatch_RBT(RBTree_t *tree, PredFn_t predFn) { + req_NonNull(tree); + + Node_t *curNode = matchLastNode(tree->root, predFn); + + // cache result of search + return setCacheInfo_Key(tree, curNode); +} + + +// Returns minimum key in given tree, if it exists +// - Updates the lookup cache - this means that the corresponding min-value +// can be efficiently accessed. +Key_t minKey_RBT(RBTree_t *tree) { + req_NonNull(tree); + + Node_t *curNode = findMinForTree(tree); + + // cache result of search + return setCacheInfo_Key(tree, curNode); +} + +// Returns maximum key in given tree +// - Updates the lookup cache - this means that the corresponding max-value +// can be efficiently accessed. +Key_t maxKey_RBT(RBTree_t *tree) { + req_NonNull(tree); + + Node_t *curNode = findMaxForTree(tree); + + // cache result of search + return setCacheInfo_Key(tree, curNode); +} + + +// Get first data element +// - Returns NULL if empty +void *getFirstElement_RBT(RBTree_t *tree) { + req_NonNull(tree); + + Node_t *curNode = findMinForTree(tree); + + // cache result of search + return setCacheInfo_Data(tree, curNode); +} + +// Get last data element +// - Returns NULL if empty +void *getLastElement_RBT(RBTree_t *tree) { + req_NonNull(tree); + + Node_t *curNode = findMaxForTree(tree); + + // cache result of search + return setCacheInfo_Data(tree, curNode); +} + +// Returns next successor key in given tree, if it exists +// - Otherwise, return NULL_KEY. +// - If allowEQ is TRUE, then can return the given key if present. +// - Given key may not itself exist in the tree. +Key_t nextKey_RBT(RBTree_t *tree, Key_t key, Boolean_t allowEQ) { + req_NonNull(tree); + + // When NULL_KEY is not permitted, return NULL_KEY for key == NULL_KEY + if (!tree->allowNullKey && key == NULL_KEY) { + return NULL_KEY; + } + + Node_t *curNode = findNextNode(tree, key, allowEQ); + + // cache result of search + return setCacheInfo_Key(tree, curNode); +} + + +// Returns predecessor key in given tree, if it exists +// - Otherwise, return NULL_KEY. +// - If allowEQ is TRUE, then can return the given key if present. +// - Given key may not itself exist in the tree. +Key_t priorKey_RBT(RBTree_t *tree, Key_t key, Boolean_t allowEQ) { + req_NonNull(tree); + + // When NULL_KEY is not permitted, return NULL_KEY for key == NULL_KEY + if (!tree->allowNullKey && key == NULL_KEY) { + return NULL_KEY; + } + + Node_t *curNode = findPrevNode(tree, key, allowEQ); + + // cache result of search + return setCacheInfo_Key(tree, curNode); +} + + +// Height of tree +int getHeight_RBT(RBTree_t *tree) { + req_NonNull(tree); + + return (nodeIsLeaf(tree->root) ? 0 : tree->root->height); +} + +// Total number of nodes in tree +int getSize_RBT(RBTree_t *tree) { + req_NonNull(tree); + + return (nodeIsLeaf(tree->root) ? 0 : tree->root->size); +} + + +// Get/Set allow updates +void setAllowUpdates_RBT(RBTree_t *tree, Boolean_t status) { + req_NonNull(tree); + + tree->allowUpd = status; +} + +Boolean_t getAllowUpdates_RBT(RBTree_t *tree) { + req_NonNull(tree); + + return tree->allowUpd; +} + + +// Set/Get allow NULL_KEY as a valid key +void setAllowNullKey_RBT(RBTree_t *tree, Boolean_t status){ + req_NonNull(tree); + + tree->allowNullKey = status; +} + +Boolean_t getAllowNullKey_RBT(RBTree_t *tree) { + req_NonNull(tree); + + return tree->allowNullKey; +} + + +// Show tree by appending to stringbuffer +// - set indent string +// - set incrment indent string +// - set compact display +// - set max depth (if positive) +// - set show details of nodes (default: TRUE) +// - set show tree tightly +// - set show tree in in-order (default) +// - set show tree in pre-order +// - set show ids (default: TRUE) +// - set show addresses (default: FALSE) +// - set show simplified addresses (e.g. addr mod 0x10000) (default: FALSE) + +// show attributes +static char *show_indent = " "; // indent string +static char *show_incrIndent = " ";; // incremental indent +static Boolean_t show_compact_display = FALSE; +static int show_max_depth = -1; +static Boolean_t show_details = FALSE; // show all node details +static Boolean_t show_tightly = FALSE; // show the tree tightly +static Boolean_t show_inorder = TRUE; // show the tree in order +static Boolean_t show_ids = TRUE; // show IDs +static Boolean_t show_addrs = FALSE; // show addresses +static Boolean_t show_simplified_addr = FALSE; // show simplified addresses (e.g. addr mod 0x10000) + +void show_RBT(RBTree_t *tree, StringBuf_t *sbuf) { + req_NonNull(tree); + req_NonNull(sbuf); + + initShowTree(sbuf); + + // updates the extended attributes of tree + if (show_details) { + updateAttrs_Tree(tree); + } + + showTree(tree); +} + +void setShow_Indent_RBT(char * indent) { + int indentLen = strlen(indent); + + if (2 <= indentLen && indentLen < MAX_INDENT_LENGTH) { + show_indent = indent; + } + else { + diagnostic("rbTree.setShow_Indent : Bad indent length: %i", indentLen); + codeError_exit(); + } +} + +void setShow_IncrIndent_RBT(char * indent) { + int indentLen = strlen(indent); + + if (2 <= indentLen && indentLen < MAX_INDENT_LENGTH) { + show_incrIndent = indent; + } + else { + diagnostic("rbTree.setShow_IncrIndent : Bad indent length: %i", indentLen); + codeError_exit(); + } +} + +void setShow_Compact_RBT(Boolean_t isCompact) { + show_compact_display = asBoolean(isCompact); +} + +// sets max depth +// - giving non-positive value removes constraint +void setShow_MaxDepth_RBT(int maxDepth) { + show_max_depth = minmax(0, maxDepth, MAX_TREE_HEIGHT); +} + +// set show details +void setShow_Details_RBT(Boolean_t details) { + show_details = details; +} + +void setShow_Tightly_RBT(Boolean_t tightly) { + show_tightly = tightly; +} + +void setShow_Inorder_RBT() { + show_inorder = TRUE; +} + +void setShow_Preorder_RBT() { + show_inorder = FALSE; +} + +void setShow_IDs_RBT(Boolean_t ids) { + show_ids = ids; +} + +void setShow_Addrs_RBT(Boolean_t addrs) { + show_addrs = addrs; +} + +void setShow_SimplifiedAddrs_RBT(Boolean_t simplified) { + show_simplified_addr = simplified; +} + + +/******************************************************************************* + Static methods +*******************************************************************************/ +static void ensureMemMgmt() { + if (rbTree_MemMgr == NULL) { + rbTree_MemMgr = new_MM(sizeof(RBTree_t)); + rbNode_MemMgr = new_MM(sizeof(Node_t)); + + // Ensure that LEAF object is initialised ... + setupLeafObject(); + } +} + + +/******************************************************************************* + Accessor methods +*******************************************************************************/ +static int nodeNumNodes(Node_t *node) { + return (nodeIsLeaf(node) ? 0 : node->size); +} + +static int nodeHeight(Node_t *node) { + return (nodeIsLeaf(node) ? 0 : node->height); +} + +// Basic version of black height +// - does not depend upon node colour. +static int nodeBHeight(Node_t *node) { + return (nodeIsLeaf(node) ? 0 : node->bHeight); +} + +// Total black-height - bHeight + colour weighting +// - This is useful for calculating node balance as it includes a value for the +// colour. +static int totalBHeight(Node_t *node) { + return (nodeBHeight(node) + (nodeIsBlack(node) ? 1 : 0)); +} + +static Boolean_t nodeIsBalanced(Node_t *node) { + if (nodeIsLeaf(node)) return TRUE; + + int leftBH = totalBHeight(node->left); + int rightBH = totalBHeight(node->right); + + return asBoolean(leftBH == rightBH); +} + +static int nodeID(Node_t *node) { + return (nodeIsLeaf(node) ? 0 : node->id); +} + +// Manage temp strings +#define MAX_TEMP_STRINGS 5 +#define TEMP_STRING_SIZE 64 +static char *tempString[MAX_TEMP_STRINGS]; +static int nextString = 0; + +static char *showNodeID(Node_t *node) { + if (tempString[nextString] == NULL) { + // allocate string + tempString[nextString] = ALLOC_STR(TEMP_STRING_SIZE); + } + + // get next string + char *output = tempString[nextString]; + + // increment index of next string + nextString += 1; + if (nextString >= MAX_TEMP_STRINGS) nextString = 0; + + sprintf(output, "id-%i (0x%lu)", nodeID(node), (Ptr_t)node); + + return output; +} + +static Colour_t nodeColour(Node_t *node) { + return (nodeIsBlack(node) ? BLACK : RED); +} + +static Boolean_t nodeIsBlack(Node_t *node) { + return (nodeIsLeaf(node) ? TRUE : node->colour == BLACK); +} + +static Boolean_t nodeIsRed(Node_t *node) { + return (nodeIsLeaf(node) ? FALSE : node->colour == RED); +} + +// This checks if node is the actual root node of given tree ... +static Boolean_t nodeIsRoot(RBTree_t *tree, Node_t *node) { + return ( tree != NULL + && nodeIsLeaf(nodeParent(node)) + && tree->root == node + && nodeIsBlack(node) + ); +} + + +static Boolean_t nodeIsLeaf(Node_t *node) { + return (node == NULL || node == LEAF); +} + +// This is the negation of the nodeIsLeaf predicate +static Boolean_t nodeIsProper(Node_t *node) { + return (node != NULL && node != LEAF); +} + +// This checks if node is the left node of its parent ... +static Boolean_t nodeIsLeft(Node_t *node) { + return (nodeIsProper(node) && node->parent->left == node); +} + +// This checks if node is the right node of its parent ... +static Boolean_t nodeIsRight(Node_t *node) { + return (nodeIsProper(node) && node->parent->right == node); +} + +static Node_t *nodeLeft(Node_t *node) { + return (nodeIsLeaf(node) ? LEAF : node->left); +} + +static Node_t *nodeRight(Node_t *node) { + return (nodeIsLeaf(node) ? LEAF : node->right); +} + +static Node_t *nodeParent(Node_t *node) { + return (nodeIsLeaf(node) ? LEAF : node->parent); +} + + +/******************************************************************************* + Comparison methods + + This uses the compare protocol for cmpKey(x, y): + LT if (x less than y) + EQ if (x equals y) + GT if (x greater than y) + +*******************************************************************************/ +static Comparison_t cmpKey(RBTree_t *tree, Key_t keyA, Key_t keyB) { + return tree->keyCompFn(keyA, keyB); +} + +static Boolean_t keyLT(RBTree_t *tree, Key_t keyA, Key_t keyB) { + return tree->keyCompFn(keyA, keyB) < 0; +} + +static Boolean_t keyEQ(RBTree_t *tree, Key_t keyA, Key_t keyB) { + return tree->keyCompFn(keyA, keyB) == 0; +} + +static Boolean_t keyGT(RBTree_t *tree, Key_t keyA, Key_t keyB) { + return tree->keyCompFn(keyA, keyB) > 0; +} + + +/******************************************************************************* + Showing colours +*******************************************************************************/ +static char *showColour(Colour_t colour) { + return (colour == BLACK ? "BLACK" : "RED"); +} + +static char *showNodeColour(Node_t *node) { + return showColour(nodeColour(node)); +} + + +/******************************************************************************* + Caching Info + - ensures consistent updates and retrievals ... +*******************************************************************************/ +static void updateCacheInfo(RBTree_t *tree, Node_t *result) { + if (nodeIsProper(result)) { + tree->cacheOn = TRUE; + tree->cachedKey = result->key; + tree->cachedData = result->data; + } + else { + tree->cacheOn = FALSE; + tree->cachedKey = NULL_KEY; + tree->cachedData = NULL; + } +} + +static Key_t setCacheInfo_Key(RBTree_t *tree, Node_t *result) { + updateCacheInfo(tree, result); + return tree->cachedKey; +} + +static void *setCacheInfo_Data(RBTree_t *tree, Node_t *result) { + updateCacheInfo(tree, result); + return tree->cachedData; +} + + +/******************************************************************************* + Finding and matching nodes +*******************************************************************************/ +static Node_t *findNode(RBTree_t *tree, Key_t key) { + Node_t *curNode = tree->root; + + // if possible find node with matching key + int indicator = 0; + while(curNode != LEAF) { + indicator = cmpKey(tree, key, curNode->key); + + if (indicator == 0) return curNode; + curNode = (indicator < 0 ? curNode->left : curNode->right); + } + + return LEAF; +} + + +static Node_t *matchFirstNode(Node_t *curNode, PredFn_t predFn) { + if (nodeIsLeaf(curNode)) return LEAF; + + Node_t *result = matchFirstNode(curNode->left, predFn); + if (nodeIsProper(result)) return result; + + if (predFn(curNode->data)) return curNode; + + return matchFirstNode(curNode->right, predFn); +} + + +static Node_t *matchLastNode(Node_t *curNode, PredFn_t predFn) { + if (nodeIsLeaf(curNode)) return LEAF; + + Node_t *result = matchLastNode(curNode->right, predFn); + if (nodeIsProper(result)) return result; + + if (predFn(curNode->data)) return curNode; + + return matchLastNode(curNode->left, predFn); +} + + +// finds the next node for a given key ... +// - the given key need not exist in the tree +// - If allowEQ is TRUE, then return node if it exists. +// - If no node exists, then return NULL +static Node_t *findNextNode(RBTree_t *tree, Key_t key, Boolean_t allowEQ) { + Node_t *parentNode = NULL; + Node_t *curNode = tree->root; + + // if possible find node with matching key + int indicator = 0; + while(nodeIsProper(curNode)) { + parentNode = curNode; + indicator = cmpKey(tree, key, curNode->key); + + // if node found then + // - if allowEQ return node + // - otherwise break + if (indicator == 0) { + if (allowEQ) return curNode; + + break; + } + + // move curNode nearer to node with target key should be + curNode = (indicator < 0 ? curNode->left : curNode->right); + } + + if (nodeIsProper(curNode)) { + // curNode->key == key + Node_t *succNode = getSuccessorNode(curNode); + if (nodeIsProper(succNode)) { + + return succNode; + } + else { + return NULL; + } + } + // curNode == LEAF + if (nodeIsProper(parentNode)) { + // get the least element greater than node + // - The parentNode is either the previous or next node for key + if (keyLT(tree, parentNode->key, key)) { + // - if parentNode's key is less than key, + // then the successor node will be immediately greater than key. + return getSuccessorNode(parentNode); + } else { + // - if parentNode's key is less than key, + // then the successor node will be immediately less than key. + // This means that parentNode's is least greater than key in the tree. + return parentNode; + } + } + else { + // This means both parentNode == curNode == LEAF i.e. undefined root + return NULL; + } +} + + +// finds the previous node for a given key ... +// - the given key need not exist in the tree +// - If allowEQ is TRUE, then return node if it exists. +// - If no node exists, then return NULL +static Node_t *findPrevNode(RBTree_t *tree, Key_t key, Boolean_t allowEQ) { + Node_t *parentNode = LEAF; + Node_t *curNode = tree->root; + + // if possible find node with matching key + int indicator = 0; + while(nodeIsProper(curNode)) { + parentNode = curNode; + indicator = cmpKey(tree, key, curNode->key); + + // if node found then + // - if allowEQ return node + // - otherwise break + if (indicator == 0) { + if (allowEQ) return curNode; + + break; + } + + // move curNode nearer to where node with target key should be + curNode = (indicator < 0 ? curNode->left : curNode->right); + } + + if (nodeIsProper(curNode)) { + // KEY FOUND!!! curNode->key == key + Node_t *prevNode = getPreviousNode(curNode); + if (nodeIsProper(prevNode)) { + return prevNode; + } + else { + return NULL; + } + } + // curNode == LEAF - i.e. key is not in the tree + if (nodeIsProper(parentNode)) { + // get the greatest element less than node + // - The parentNode is either the previous or next node for key + if (keyGT(tree, parentNode->key, key)) { + // - if parentNode's key is greater than key, + // then the previous node will be immediately less than key. + return getPreviousNode(parentNode); + } else { + // - if parentNode's key is less than key, + // then the successor node will be immediately greater than key. + // This means that parentNode's is greatest less than key in the tree. + return parentNode; + } + } + else { + // This means both parentNode == curNode == LEAF + return NULL; + } +} + +static Node_t *findMinForTree(RBTree_t *tree) { + return getLeftmostNode(tree->root); +} + +static Node_t *findMaxForTree(RBTree_t *tree) { + return getRightmostNode(tree->root); +} + + +static Node_t *getSuccessorNode(Node_t *node) { + if (nodeIsLeaf(node)) { + return LEAF; + } + + if (nodeIsLeaf(node->right)) { + + // crawl back up the tree to find successor (if possible) + Node_t *curNode = node; + Node_t *parentNode = curNode->parent; + + while (nodeIsProper(parentNode)) { + if (curNode == parentNode->left) { + return parentNode; + } + + // Ascending the tree ... + curNode = parentNode; + parentNode = curNode->parent; + } + + return LEAF; + + } else { + + return getLeftmostNode(node->right); + } +} + + +static Node_t *getPreviousNode(Node_t *node) { + if (nodeIsLeaf(node)) { + return LEAF; + } + + if (nodeIsLeaf(node->left)) { + + // crawl back up the tree to find predecessor (if possible) + Node_t *curNode = node; + Node_t *parentNode = curNode->parent; + + while (nodeIsProper(parentNode)) { + if (curNode == parentNode->right) { + return parentNode; + } + + // Ascending the tree ... + curNode = parentNode; + parentNode = curNode->parent; + } + + return LEAF; + + } else { + + return getRightmostNode(node->left); + } +} + +static Node_t *getLeftmostNode(Node_t *node) { + if (nodeIsLeaf(node)) return node; + + Node_t *parentNode = nodeParent(node); + Node_t *curNode = node; + + while (nodeIsProper(curNode)) { + parentNode = curNode; + curNode = curNode->left; + } + + return parentNode; +} + +static Node_t *getRightmostNode(Node_t *node) { + if (nodeIsLeaf(node)) return LEAF; + + Node_t *parentNode = nodeParent(node); + Node_t *curNode = node; + + while (nodeIsProper(curNode)) { + parentNode = curNode; + curNode = curNode->right; + } + + return parentNode; +} + + +/******************************************************************************* + Allocation/deallocation +*******************************************************************************/ +// Allocate a fresh tree node. +// - All nodes are added as tips of the tree (i.e. with null descendents). +// - They all start out as coloured RED ... +static Node_t *allocate_Node(Key_t key, void *dataItem) { + // ensure that the allocation structures exist ... + ensureMemMgmt(); + + Node_t *newNode = allocateObject_MM(rbNode_MemMgr); + + // initialise attributes + newNode->left = LEAF; + newNode->right = LEAF; + newNode->parent = LEAF; + + newNode->id = nextNodeID; // unique node id - these should never be repeated. + newNode->colour = RED; // All allocated tree nodes start out as RED + + // extended attributes + newNode->size = 1; // total number of nodes (including this one) - NULL + newNode->height = 1; // current height of nodes (including this one) + newNode->bHeight = 1; // blackHeight of this node is 1 (bHeight of LEAF's is 0) + + // keys and data + newNode->key = key; + newNode->data = dataItem; + + // increment node id .. + nextNodeID += 1; + + return newNode; +} + +static void deallocate_Node(RBTree_t *tree, Node_t *node) { + if (tree == NULL) return; + if (nodeIsLeaf(node)) return; + + // nullify node + NULLIFY_OBJ(node, Node_t); + + // recycle the current tree object + deallocateObject_MM(rbNode_MemMgr, sizeof(Node_t), node); +} + + +static void deallocate_All(RBTree_t *tree, Node_t *node, VoidFn_t finalObjFn) { + if (tree == NULL) return; + if (nodeIsLeaf(node)) return; + + // finalise all data below + finalObjFn(node->data); + deallocate_All(tree, node->left, finalObjFn); + deallocate_All(tree, node->right, finalObjFn); + + // nullify node + NULLIFY_OBJ(node, Node_t) + + // recycle the current tree object + deallocateObject_MM(rbNode_MemMgr, sizeof(Node_t), node); +} + + +/******************************************************************************* + Fixing the RB invariants + + On insert and delete actions, the tree will have its RB invaraants broken. + + These are fixed below (by suitable recolouring and rotations) which change topology + without affecting the overall ordering of elements. +*******************************************************************************/ + +// This updates the tree, starting with the new node (coloured RED). This works by +// rearranging nodes to eliminate RED nodes with RED parents. +static void *insertNode(RBTree_t *tree, Key_t key, void *val) { + Node_t *curNode, *parentNode, *newNode; + + // find future parent + curNode = tree->root; + parentNode = NULL; + + while (curNode != LEAF) { + if (keyEQ(tree, key, curNode->key)) { + if (tree->allowUpd) { + + // update existing data + void * prevData = curNode->data; + curNode->data = val; + + return prevData; + } + + //printf("insertNode - found DUPLICATED node with key = %s\n", showKey(key)); + return NULL; + } + + parentNode = curNode; + curNode = (keyLT(tree, key, curNode->key) ? curNode->left : curNode->right); + } + + // setup new node + newNode = allocate_Node(key, val); + newNode->parent = parentNode; + + // insert node in tree + if (nodeIsProper(parentNode)) { + if (keyLT(tree, key, parentNode->key)) + parentNode->left = newNode; + else + parentNode->right = newNode; + + } else { + + tree->root = newNode; + + } + + // Mark the newNode and its ancestors as needing update. + markUpdateNeeded(newNode); + + fixupInsert(tree, newNode); + + return NULL; +} + +static void fixupInsert(RBTree_t *tree, Node_t *newNode) { + req_NonNull(tree); + req_NonNull(newNode); + + // maintain red-black tree balance + // after inserting node newNode + + Node_t *fixupNode = newNode; + + // check red-black properties + while (fixupNode != tree->root && fixupNode->parent->colour == RED) { + // we have a violation + if (fixupNode->parent == fixupNode->parent->parent->left) { + Node_t *uncleNode = fixupNode->parent->parent->right; + + // Mark the uncleNode and its ancestors as needing update. + //markUpdateNeeded(uncleNode); + + if (uncleNode->colour == RED) { + + // uncle is RED + fixupNode->parent->colour = BLACK; + uncleNode->colour = BLACK; + fixupNode->parent->parent->colour = RED; + fixupNode = fixupNode->parent->parent; + } else { + + // uncle is BLACK + if (fixupNode == fixupNode->parent->right) { + // make fixupNode a left child + fixupNode = fixupNode->parent; + + leftRotate(tree, fixupNode); + } + + // recolor and rotate + fixupNode->parent->colour = BLACK; + fixupNode->parent->parent->colour = RED; + + rightRotate(tree, fixupNode->parent->parent); + } + } else { + + // mirror image of above code + Node_t *uncleNode = fixupNode->parent->parent->left; + + // Mark the uncleNode and its ancestors as needing update. + //markUpdateNeeded(uncleNode); + + if (uncleNode->colour == RED) { + + // uncle is RED + fixupNode->parent->colour = BLACK; + uncleNode->colour = BLACK; + fixupNode->parent->parent->colour = RED; + fixupNode = fixupNode->parent->parent; + } else { + + // uncle is BLACK + if (fixupNode == fixupNode->parent->left) { + fixupNode = fixupNode->parent; + + rightRotate(tree, fixupNode); + } + fixupNode->parent->colour = BLACK; + fixupNode->parent->parent->colour = RED; + + leftRotate(tree, fixupNode->parent->parent); + } + } + } + + tree->root->colour = BLACK; +} + + +/******************************************************************************* + Deleting nodes + - Nodes are deleted by rearranging information and deleting a convenient node. + - The subtlety is that the target node may not actually be deleted - instead + a more convenient node is found and information rearranged so as to preserve + content. +*******************************************************************************/ +static void removeInfo(RBTree_t *tree, Node_t *targetNode) { + req_NonNull(targetNode); + + if (targetNode == LEAF) { + diagnostic("removeInfo : Attempting to delete LEAF node."); + codeError_exit(); + } + + Node_t *movedNode, *delNode = LEAF; + + // Define this node to be the replacement + Node_t *replaceNode = LEAF; + + if (targetNode->left == LEAF || targetNode->right == LEAF) { + // delNode has a LEAF node as a child + delNode = targetNode; + + } else { + // targetNode->left != LEAF && targetNode->right != LEAF + // - both descendents of targetNode are proper nodes. + + // Find tree successor with a LEAF node as a child + Node_t *succNode = targetNode->right; + while (succNode->left != LEAF) { + succNode = succNode->left; + } + + // delNode != LEAF && delNode->left == LEAF + delNode = succNode; + replaceNode = targetNode; + + // NOTE: delNode = succNode != targetNode = replaceNode + // In this case, the node to be deleted is the successor node, not the targetNode. + } + + // delNode now has at most one non-LEAF child ... + // - This non-LEAF child has to be moved. + // - it could still have two LEAF children (i.e. be a "tip" node) + + // set movedNode to be delNode's non-LEAF child (if possible) + if (nodeIsProper(delNode->left)) + // movedNode cannot be a LEAF + movedNode = delNode->left; + else + // movedNode could be a LEAF here ... + movedNode = delNode->right; + + // Remove delNode from the parent chain + // - Although the movedNode could be LEAF, the parent pointer may be updated ... + movedNode->parent = delNode->parent; + if (nodeIsProper(delNode->parent)) + if (delNode == delNode->parent->left) + delNode->parent->left = movedNode; + else + delNode->parent->right = movedNode; + else + // delNode->parent == NULL, thus delNode is currently root + tree->root = movedNode; + + if (delNode != targetNode) { + // replaceNode must not be equal to LEAF + req_Distinct(replaceNode, LEAF); + + // delNode and replaceNode must be distinct. + req_Distinct(delNode, replaceNode); + + // relocating information to be retained + + replaceNode->key = delNode->key; + replaceNode->data = delNode->data; + + // Nullify old info ... + delNode->key = NULL_KEY; + delNode->data = NULL; + } + + // Mark the movedNode and its ancestors as needing update. + markUpdateNeeded(movedNode); + + // Mark the delNode and its ancestors as needing update. + markUpdateNeeded(delNode); + + // Check if fixup is needed ... + if (delNode->colour == BLACK) { + // Node to be deleted is BLACK, thus changing the number of BLACK nodes + // - hence fixup is needed to restore red-black properties + fixupDelete (tree, movedNode); + } + // Recycle delNode + deallocate_Node(tree, delNode); +} + + +static void fixupDelete(RBTree_t *tree, Node_t *fixupNode) { + + // maintain red-black tree balance + + while (fixupNode != tree->root && fixupNode->colour == BLACK) { + + if (fixupNode == fixupNode->parent->left) { + + Node_t *siblingNode = fixupNode->parent->right; + + // Mark the siblingNode and its ancestors as needing update. + markUpdateNeeded(siblingNode); + + if (siblingNode->colour == RED) { + + siblingNode->colour = BLACK; + fixupNode->parent->colour = RED; + + leftRotate (tree, fixupNode->parent); + + siblingNode = fixupNode->parent->right; + + // Mark the siblingNode and its ancestors as needing update. + markUpdateNeeded(siblingNode); + } + + if (siblingNode->left->colour == BLACK && siblingNode->right->colour == BLACK) { + siblingNode->colour = RED; + + fixupNode = fixupNode->parent; + + } else { + if (siblingNode->right->colour == BLACK) { + siblingNode->left->colour = BLACK; + siblingNode->colour = RED; + + rightRotate(tree, siblingNode); + + siblingNode = fixupNode->parent->right; + + // Mark the siblingNode and its ancestors as needing update. + markUpdateNeeded(siblingNode); + } + + siblingNode->colour = fixupNode->parent->colour; + fixupNode->parent->colour = BLACK; + siblingNode->right->colour = BLACK; + + leftRotate(tree, fixupNode->parent); + + fixupNode = tree->root; + } + + } else { + + Node_t *siblingNode = fixupNode->parent->left; + + // Mark the siblingNode and its ancestors as needing update. + markUpdateNeeded(siblingNode); + + if (siblingNode->colour == RED) { + siblingNode->colour = BLACK; + fixupNode->parent->colour = RED; + + rightRotate(tree, fixupNode->parent); + + siblingNode = fixupNode->parent->left; + + // Mark the siblingNode and its ancestors as needing update. + markUpdateNeeded(siblingNode); + } + + if (siblingNode->right->colour == BLACK && siblingNode->left->colour == BLACK) { + siblingNode->colour = RED; + + fixupNode = fixupNode->parent; + + } else { + if (siblingNode->left->colour == BLACK) { + siblingNode->right->colour = BLACK; + siblingNode->colour = RED; + + leftRotate(tree, siblingNode); + + siblingNode = fixupNode->parent->left; + + // Mark the siblingNode and its ancestors as needing update. + markUpdateNeeded(siblingNode); + } + + siblingNode->colour = fixupNode->parent->colour; + fixupNode->parent->colour = BLACK; + siblingNode->left->colour = BLACK; + + rightRotate (tree, fixupNode->parent); + + fixupNode = tree->root; + } + } + } + + fixupNode->colour = BLACK; +} + + +/******************************************************************************* + Tree Rotations +*******************************************************************************/ +// Left rotate moves a pivot node P left-wards down the tree (away from the root) +// and moves its right tree R to become its parent. +// +// - Right rotate is the inverse. +// +// - Requires node R to be _right_ node of pivot P. +// +// - Transforms: P(TA, R(TB, TC)) To: R(P(TA, TB), TC) +// where P = pivot, R = right +// +// - Preserves ordering: TA < P < TB < R < TC +// +// - This transform does not change position of: +// - TA, left node of P +// - TC, right node of R +static void leftRotate(RBTree_t *tree, Node_t *pivotNode) { + req_NonNull(tree); + req_NonNull(pivotNode); + + if (nodeIsLeaf(pivotNode)) { + diagnostic("rightRotate : pivot node is LEAF"); + codeError_exit(); + } + + Node_t *newPivotNode = pivotNode->right; + + // set pivotNode->right + pivotNode->right = newPivotNode->left; + if (nodeIsProper(newPivotNode->left)) newPivotNode->left->parent = pivotNode; + + // set newPivotNode->parent + if (nodeIsProper(newPivotNode)) newPivotNode->parent = pivotNode->parent; + if (nodeIsProper(pivotNode->parent)) { + if (pivotNode == pivotNode->parent->left) + pivotNode->parent->left = newPivotNode; + else + pivotNode->parent->right = newPivotNode; + } else { + // new root ... + tree->root = newPivotNode; + } + + // link pivotNode and newPivotNode + newPivotNode->left = pivotNode; + if (pivotNode != LEAF) pivotNode->parent = newPivotNode; + + // mark nodes that need updating ... + markUpdateNeeded(pivotNode); +} + + +// Right rotate moves a pivot node P right-wards down the tree (away from the root) +// and moves its left tree L to become its parent. +// +// - Left rotate is the inverse. +// +// - Requires node L to be _left_ node of pivot P. +// +// - Transforms: P(L(TA, TB), TC)) To: L(TA, P(TB, TC)) +// where P = pivot, L = left +// +// - Preserves ordering: TA < L < TB < P < TC +// +// - This transform does not change position of: +// - TA, left node of L +// - TC, right node of P +static void rightRotate(RBTree_t *tree, Node_t *pivotNode) { + req_NonNull(tree); + req_NonNull(pivotNode); + + if (nodeIsLeaf(pivotNode)) { + diagnostic("rightRotate : pivot node is LEAF"); + codeError_exit(); + } + + Node_t *newPivotNode = pivotNode->left; + + // setup pivotNode->left + pivotNode->left = newPivotNode->right; + if (nodeIsProper(newPivotNode->right)) newPivotNode->right->parent = pivotNode; + + // setup newPivotNode->parent + if (nodeIsProper(newPivotNode)) newPivotNode->parent = pivotNode->parent; + + if (nodeIsProper(pivotNode->parent)) { + if (pivotNode == pivotNode->parent->right) + pivotNode->parent->right = newPivotNode; + else + pivotNode->parent->left = newPivotNode; + } else { + // new root ... + tree->root = newPivotNode; + } + + // link pivotNode and newPivotNode + newPivotNode->right = pivotNode; + if (pivotNode != LEAF) pivotNode->parent = newPivotNode; + + // mark nodes that need updating ... + markUpdateNeeded(pivotNode); +} + + +/******************************************************************************* + Attribute maintenance +*******************************************************************************/ +static void updateAttrs_Tree(RBTree_t *tree) { + req_NonNull(tree); + + // check for update + if (!tree->root->needUpd) return; + + updateAttrs_All(tree->root); +} + +static void markUpdateNeeded(Node_t *node) { + + while(nodeIsProper(node)) { + // Check if node already marked + if (node->needUpd) return; + + // Mark this node as needing needUpd + node->needUpd = TRUE; + + // Now mark the _parent_ (if any) ... + // Eventually this reaches the root or + // some node already marked as needing update. + node = node->parent; + } +} + +static void updateAttrs_All(Node_t *node) { + if (nodeIsLeaf(node)) return; + + if (!node->needUpd) return; + + updateAttrs_All(node->left); + updateAttrs_All(node->right); + + // Update current node using up-to-date info. from sub-trees. + updateAttrs_Node(node); +} + +static void forcedUpdateAttrs(Node_t *node) { + if (nodeIsLeaf(node)) return; + + forcedUpdateAttrs(node->left); + forcedUpdateAttrs(node->right); + + // Update current node using up-to-date info. from sub-trees. + updateAttrs_Node(node); +} + +// Just updates extended attributes for this node assuming data from sub-nodes is up-to-date +// - Returns TRUE if updates were made. +static Boolean_t updateAttrs_Node(Node_t *node) { + if (nodeIsLeaf(node)) return FALSE; + + Boolean_t updateMade = FALSE; + + // Update height + int leftHeight = nodeHeight(node->left); + int rightHeight = nodeHeight(node->right); + + int newHeight = 1 + max(leftHeight, rightHeight); + + if (newHeight != node->height) { + node->height = newHeight; + updateMade = TRUE; + } + + // Update bHeight + int leftBH = totalBHeight(node->left); // Calc. bHeight, incl. colour weighting ... + int rightBH = totalBHeight(node->right); + + int newBH = max(leftBH, rightBH); // This does NOT include colour weighting for the current node. + + if (newBH != node->bHeight) { + node->bHeight = newBH; + updateMade = TRUE; + } + + // Update size + int leftNumNodes = nodeNumNodes(node->left); + int rightNumNodes = nodeNumNodes(node->right); + + int newNumNodes = 1 + leftNumNodes + rightNumNodes; + + if (newNumNodes != node->size) { + node->size = newNumNodes; + updateMade = TRUE; + } + + // Clear the update flag ... + node->needUpd = FALSE; + + return updateMade; +} + + +/******************************************************************************* + Check tree and Red-Black Invariants + + - This checks structure of given tree and reports any issues found. +*******************************************************************************/ +// Utility to check tree for integrity (useful for testing) +Boolean_t checkTree_RBT(RBTree_t *tree) { + if (tree == NULL) return TRUE; + if (nodeIsLeaf(tree->root)) return TRUE; + + Boolean_t treeStatus = TRUE; + Boolean_t rootStatus = TRUE; + + Boolean_t outputStatus = outputCheckReports; + + outputCheckReports = (abortOnCheckFailure | outputStatus); + + if (!nodeIsBlack(tree->root)) { + if (outputCheckReports) { + printf("checkTree_RBT: Tree root 0x%lu is not BLACK.", convPtr(tree->root)); + } + rootStatus = FALSE; + } + + // check the tree .... + treeStatus = check_treenode(tree->root); + + if (!treeStatus && abortOnCheckFailure) { + printf("\n\n++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); + printf("FAILED TREE:\n\n"); + + StringBuf_t *sBuf = new_SB(); + show_RBT(tree, sBuf); + print_SB(sBuf); + + diagnostic("Aborting - checkTree_RBT failed"); + error_exit(); + } + + // resetting outputCheckReports + outputCheckReports = outputStatus; + + return (rootStatus && treeStatus); +} + + +static void showReport(Node_t *node, char *msg) { + if (outputCheckReports) { + Key_t key = (nodeIsLeaf(node) ? NULL_KEY : node->key); + + if (show_ids) { + printf(" Node %s (key: %s): %s\n", showNodeID(node), showKey(key), msg); + } else { + printf(" Node 0x%lu (key: %s): %s\n", convPtr(node), showKey(key), msg); + } + } +} + + +// Checks and updates nodes +static Boolean_t check_treenode(Node_t *node) { + if (nodeIsLeaf(node)) return TRUE; + + // check and update sub-trees + Boolean_t leftStatus = check_treenode(node->left); + Boolean_t rightStatus = check_treenode(node->right); + + // Update node attributes + Boolean_t updateMade = updateAttrs_Node(node); + if (updateMade) { + //showReport(node, "Updates to attributes were made for node."); + diagnostic("Updates to attributes were made for node = %s", showNodeID(node)); + error_exit(); + } + + // Check subnode parents ... + Boolean_t parentStatus = check_subnode_parents(node); + + // Check RB properties ... + Boolean_t nodeStatus = check_RB_properties(node); + + return (nodeStatus && parentStatus && leftStatus && rightStatus); +} + +static Boolean_t check_subnode_parents(Node_t *node) { + if (nodeIsLeaf(node)) return TRUE; + + Boolean_t status = TRUE; + + // check left parent + if (nodeIsProper(node->left)) { + if (node->left->parent != node) { + showReport(node, "Parent of (node->left) is not equal to node"); + status = FALSE; + } + } + + // check right parent + if (nodeIsProper(node->right)) { + if (node->right->parent != node) { + showReport(node, "Parent of (node->right) is not equal to node"); + status = FALSE; + } + } + + return status; +} + +static char __checkMsgBuffer[1024]; +static Boolean_t check_RB_properties(Node_t *node) { + if (nodeIsLeaf(node)) return TRUE; + + Key_t key = node->key; + + Boolean_t status = TRUE; + + // Check node colour property + if (nodeIsRed(node)) { + if (nodeIsRed(node->left)) { + showReport(node, "Colour property violated (both node and node-left are RED)"); + status = FALSE; + } + + if (nodeIsRed(node->right)) { + showReport(node, "Colour property violated (both node and node-right are RED)"); + status = FALSE; + } + } + + // Check black-height balance property + if (!nodeIsBalanced(node)) { + // construct tmp message ... + sprintf(__checkMsgBuffer, "Black height property broken: left BH = %i =/= right BH = %i", + totalBHeight(node->left), + totalBHeight(node->right)); + + showReport(node, __checkMsgBuffer); + + status = FALSE; + } + + return status; +} + + +/******************************************************************************* + Showing Keys and Pointers +*******************************************************************************/ +#define INT_KEY_LIMIT 100001 +static char keyBuffer[LINE_BUFSIZE+1]; + +static char *showKey(Key_t key) { + if (key == NULL_KEY) return "NULL_KEY"; + + long keyVal = (long)key; + + if (keyVal < -INT_KEY_LIMIT || keyVal > INT_KEY_LIMIT) { + sprintf(keyBuffer, "0x%lu", convPtr((void *)key)); + } else { + sprintf(keyBuffer, "%i", (int)keyVal); + } + + return keyBuffer; +} + +// This will convert pointers for display just to show the last two bytes +static Ptr_t convPtr(void *addr) { + Ptr_t ptr = (Ptr_t)addr; + return (show_simplified_addr ? ptr % 0x10000 : ptr); +} + +/******************************************************************************* + Showing RB Trees +*******************************************************************************/ +static void initShowTree(StringBuf_t *sbuf); +static void showTree(RBTree_t *mTree); + +static void setCurIndent(int indentLevel); +static void showTreeNode(Node_t *node, int indentLevel); +static void showNodeCore(Node_t *node, int indentLevel); + +static StringBuf_t *curSBuf = NULL; +static int maxLevel = 15; +static char *curIndent = NULL; + +static int indentLen = 0; +static int incrIndentLen = 0; +static int totalIndentLength = 0; + +static void setCurIndent(int indentLevel) { + + // ensure initialisation + if (curIndent == NULL) { + totalIndentLength = LINE_BUFSIZE+1; + curIndent = ALLOC_ARR(totalIndentLength, char); + + // initialising lengths etc. ... + indentLen = strlen(show_indent); + incrIndentLen = strlen(show_incrIndent); + + if (incrIndentLen <= 0) { + diagnostic("setCurIndent: Bad incrIndentLen = %i", incrIndentLen); + codeError_exit(); + } + } + + // initialise by copying indent into curIndent + strcpy(curIndent, show_indent); + + // set starting point + char *nextIndent = curIndent+indentLen; + + for (int i = 0; i < indentLevel; i++) { + // copy incremental + strcpy(nextIndent, show_incrIndent); + nextIndent += incrIndentLen; + } +} + +static void showNodeCore(Node_t *node, int indentLevel) { + if (nodeIsLeaf(node)) return; + + if (!show_tightly) { + addItems_SB(curSBuf, " :\n"); + } + addItems_SB(curSBuf, "%4i:%sNode key: %s\n", indentLevel, curIndent, showKey(node->key)); + + if (show_ids) { + addItems_SB(curSBuf, " ...:%sNode ID: %s\n", curIndent, showNodeID(node)); + addItems_SB(curSBuf, " ...:%sParent ID: %s\n", curIndent, showNodeID(nodeParent(node))); + } + + if (show_addrs) { + addItems_SB(curSBuf, " ...:%sNode obj: 0x%lu\n", curIndent, convPtr(node)); + addItems_SB(curSBuf, " ...:%sParent obj: 0x%lu\n", curIndent, convPtr(nodeParent(node))); + } + + char *balanced = (nodeIsBalanced(node) ? "" : " *** UNBALANCED ***"); + + if (show_details) { + addItems_SB(curSBuf, " ...:%sColour: %s%s\n", curIndent, showNodeColour(node), balanced); + addItems_SB(curSBuf, " ...:%sBHeight: %i\n", curIndent, nodeBHeight(node)); + addItems_SB(curSBuf, " ...:%sHeight: %i\n", curIndent, node->height); + addItems_SB(curSBuf, " ...:%s# Nodes: %i\n", curIndent, nodeNumNodes(node)); + } +} + +static void showSpacerLine() { + if (!show_tightly) { + addItems_SB(curSBuf, " :\n"); + } +} + +static char *showLeaf(Node_t *node) { + return (node == NULL ? "NULL" : node == LEAF ? "LEAF" : "???"); +} + +static void showTreeNode(Node_t *node, int indentLevel) { + + // set current indent level + setCurIndent(indentLevel); + + if (nodeIsLeaf(node)) { + addItems_SB(curSBuf, "%4i:%s%s\n", indentLevel, curIndent, showLeaf(node)); + return; + } + + // check if indentLevel exceeds maxLevel + if (indentLevel > maxLevel) { + addItems_SB(curSBuf, "%4i:%s...\n", indentLevel, curIndent); + return; + } + + // Display the node pre-order + if (!show_inorder) { + showNodeCore(node, indentLevel); + + showSpacerLine(); + } + + if (nodeIsLeaf(node->left)) { + if (show_ids) { + addItems_SB(curSBuf, "%4i:%sLEFT (for node %s): %s\n", indentLevel, curIndent, showNodeID(node), showLeaf(node->left)); + } else { + addItems_SB(curSBuf, "%4i:%sLEFT (for node 0x%lu): %s\n", indentLevel, curIndent, convPtr(node), showLeaf(node->left)); + } + + } else { + if (show_ids) { + addItems_SB(curSBuf, "%4i:%sLEFT (for node %s):\n", indentLevel, curIndent, showNodeID(node)); + } else { + addItems_SB(curSBuf, "%4i:%sLEFT (for node 0x%lu):\n", indentLevel, curIndent, convPtr(node)); + } + showTreeNode(node->left, indentLevel+1); + + setCurIndent(indentLevel); + } + + showSpacerLine(); + + // Display the node in-order + if (show_inorder) { + showNodeCore(node, indentLevel); + + showSpacerLine(); + } + + if (nodeIsLeaf(node->right)) { + if (show_ids) { + addItems_SB(curSBuf, "%4i:%sRIGHT (for node %s): %s\n", indentLevel, curIndent, showNodeID(node), showLeaf(node->right)); + } else { + addItems_SB(curSBuf, "%4i:%sRIGHT (for node 0x%lu): %s\n", indentLevel, curIndent, showNodeID(node), showLeaf(node->right)); + } + + } else { + if (show_ids) { + addItems_SB(curSBuf, "%4i:%sRIGHT (for node %s):\n", indentLevel, curIndent, showNodeID(node)); + } else { + addItems_SB(curSBuf, "%4i:%sRIGHT (for node 0x%lu):\n", indentLevel, curIndent, convPtr(node)); + } + showTreeNode(node->right, indentLevel+1); + } + + //addItems_SB(curSBuf, " :\n"); + +} + + +static void initShowTree(StringBuf_t *sbuf) { + // set the string buffer + curSBuf = sbuf; +} + +static void showTree(RBTree_t *tree) { + req_NonNull(tree); + + setCurIndent(0); + addItems_SB(curSBuf, "%sRBTree <size:%i>\n", curIndent, getSize_RBT(tree)); + + // show the full tree if not compact ... + if (!show_compact_display) { + showTreeNode(tree->root, 0); + } +} diff --git a/hash_fusion/lib/rbTree.h b/hash_fusion/lib/rbTree.h new file mode 100644 index 0000000000..41247115aa --- /dev/null +++ b/hash_fusion/lib/rbTree.h @@ -0,0 +1,229 @@ +#ifndef __RB_TREE_H__ +#define __RB_TREE_H__ + +/******************************************************************************* + rbTree.h + + Red-Black Trees + + - Implements ordered keys mapping to value (i.e. ordered treemap). + + Provides set and/or map abstractions. + + - Significant input from: + + Chapter 12, Binary Search Trees + + Chapter 13, Red-Black Trees + + from Cormen et al, Introduction to Algorithms, 3rd Ed. MIT Press + + Keys are encoded as an "opaque" type (see utils.h) + + Red-Black properties: + ===================== + - Each internal node has colour either RED or BLACK. + + - The root of the tree is BLACK. + + - If a node is RED, then both of its decendants must be BLACK. + + - All terminal nodes (i.e. NULLs) are BLACK. + + - All new nodes start out being coloured RED. + + - For every node, the total number of BLACK nodes is the same for each + decendant path from the node to the leaves. + + Author: brian.monahan@hpe.com + + (c) Copyright 2017 Hewlett Packard Enterprise Development LP + + 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. + + 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. + +*******************************************************************************/ + +#include "utils.h" +#include "stringbuffer.h" + +// Red-Black Tree structure +// - This encodes the root of the tree itself. +typedef struct rbTree RBTree_t; + + +/******************************************************************************* + Parameters + - These parameters are typically varied for testing purposes. + - As they affect all instances, they should not be relied upon in production. +*******************************************************************************/ +// Enable/disable internal checking of RB tree +Boolean_t doInternalChecks; + +// Enable/disable output of reports from checking (see: checkTree_RBT) +Boolean_t outputCheckReports; + +// Enable balancing +Boolean_t doBalancing; + +// Abort when checking the tree fails +// - When true, enables the output of reports when running checkTree_RBT ... +Boolean_t abortOnCheckFailure; + + +/******************************************************************************* + Methods +*******************************************************************************/ +// Allocate an RBTree_t object ... +// +// - keyCompFn - Used to compare keys - as a linear (less-than) ordering. +// - Take care with NULL_KEYs - these may be either significant or not, +// depending upon application +// - If function is NULL, then the standard < ordering on unsigned long values is used. +// +RBTree_t *new_RBT(CompareFn_t keyCompFn); + +// Deallocate an RBTree object ... +void deallocate_RBT(void *item); + +// Deallocate an RBTree object ... with specific object finaliser +void deallocateWithFinaliser_RBT(void *item, VoidFn_t finalObjFn); + +// Set object finaliser function ... +// - No finalisation happens for data items unless this is set. +void setFinaliser_RBT(RBTree_t *tree, VoidFn_t finalObjFn); + +// Inserts data under given key into given tree ... +// - If key already exists in tree and updates allowed: +// + replaces previous data with dataItem. +// + return previous data. +// - Otherwise, insert new dataItem and return NULL. +// - If updates not allowed only new values are inserted, +// - In this case, NULL is always returned. +// - In general, use the size of tree to determine when new elements were added. +void *insert_RBT(RBTree_t *tree, Key_t key, void *dataItem); + +// Deletes data under given key from given tree. +// - If found, returns the data pointer found. +// - Otherwise return NULL +void *delete_RBT(RBTree_t *tree, Key_t key); + +// Checks that given key belongs to given tree. +// - Successful lookups are cached. +Boolean_t member_RBT(RBTree_t *tree, Key_t key); + +// Get first data element +// - Returns NULL if empty +void *getFirstElement_RBT(RBTree_t *tree); + +// Get last data element +// - Returns NULL if empty +void *getLastElement_RBT(RBTree_t *tree); + +// Lookup data in tree for the given key +// - If found, returns the corresponding data pointer for the given key. +// - Otherwise return NULL +// - The last successful lookup is cached. +void *lookup_RBT(RBTree_t *tree, Key_t key); + +// find key of first element matching the predicate ... +// - finds the key of the first/least element in the tree satisfying the predicate +Key_t findFirstMatch_RBT(RBTree_t *tree, PredFn_t predFn); + +// find key of last element matching the predicate ... +// - finds the key of the last/greatest element in the tree satisfying the predicate +Key_t findLastMatch_RBT(RBTree_t *tree, PredFn_t predFn); + +// Returns minimum key in given tree, if it exists +// - Updates the lookup cache - this means that the corresponding min-value +// can be efficiently accessed. +// - Otherwise, return NULL_KEY. +Key_t minKey_RBT(RBTree_t *tree); + +// Returns maximum key in given tree +// - Updates the lookup cache - this means that the corresponding max-value +// can be efficiently accessed. +// - Otherwise, return NULL_KEY. +Key_t maxKey_RBT(RBTree_t *tree); + +// Returns next successor key in given tree, if it exists +// - Otherwise, return NULL_KEY. +// - If allowEQ is TRUE, then can return the given key if present. +// - Given key may not itself exist in the tree. +Key_t nextKey_RBT(RBTree_t *tree, Key_t key, Boolean_t allowEQ); + +// Returns predecessor key in given tree, if it exists +// - Otherwise, return NULL_KEY. +// - If allowEQ is TRUE, then can return the given key if present. +// - Given key may not itself exist in the tree. +Key_t priorKey_RBT(RBTree_t *tree, Key_t key, Boolean_t allowEQ); + +// Utility to check tree for integrity (useful for testing) +Boolean_t checkTree_RBT(RBTree_t *tree); + +// Height of tree +int getHeight_RBT(RBTree_t *tree); + +// Total number of nodes in tree +int getSize_RBT(RBTree_t *tree); + +// Set/Get allow updates +void setAllowUpdates_RBT(RBTree_t *tree, Boolean_t status); +Boolean_t getAllowUpdates_RBT(RBTree_t *tree); + +// Set/Get allow NULL_KEY as a valid key +void setAllowNullKey_RBT(RBTree_t *tree, Boolean_t status); +Boolean_t getAllowNullKey_RBT(RBTree_t *tree); + + +// Show tree by appending to stringbuffer +// - set indent string +// - set incrment indent string +// - set compact display +// - set max depth (if positive) +// - set show details of nodes (default: TRUE) +// - set show tree tightly +// - set show tree in in-order (default) +// - set show tree in pre-order +// - set show ids (default: TRUE) +// - set show addresses (default: FALSE) +// - set show simplified addresses (e.g. addr mod 0x10000) (default: FALSE) + +void show_RBT(RBTree_t *tree, StringBuf_t *sbuf); +void setShow_Indent_RBT(char * indent); +void setShow_IncrIndent_RBT(char * indent); +void setShow_Compact_RBT(Boolean_t isCompact); +void setShow_MaxDepth_RBT(int maxDepth); +void setShow_Details_RBT(Boolean_t details); +void setShow_Tightly_RBT(Boolean_t tightly); +void setShow_Inorder_RBT(); +void setShow_Preorder_RBT(); +void setShow_IDs_RBT(Boolean_t ids); +void setShow_Addrs_RBT(Boolean_t addrs); +void setShow_SimplifiedAddrs_RBT(Boolean_t simplified); + + +// Maximum indent length +#define MAX_INDENT_LENGTH 20 + +// Maximum Tree Height ... +#define MAX_TREE_HEIGHT 32 + +#endif diff --git a/hash_fusion/lib/stringbuffer.c b/hash_fusion/lib/stringbuffer.c new file mode 100644 index 0000000000..cdbde9d273 --- /dev/null +++ b/hash_fusion/lib/stringbuffer.c @@ -0,0 +1,179 @@ +/* stringbuffer.c + + String buffer are used to accumulate strings, typically for output. + + They are essentially the same as bytevectors ... + The sentinel byte (i.e. at end of each bytevector) is NULL to allow for C-strings. + + Author: brian.monahan@hpe.com + + (c) Copyright 2017 Hewlett Packard Enterprise Development LP + + 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. + + 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. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "utils.h" +#include "stringbuffer.h" + + +// local defines +#define getContent(sbuf) ((char *)getContent_BV(sBuf)) + + +// New string buffer with initial capacity +StringBuf_t *new_SB() { + return allocate_SB(DEFAULT_STRINGBUFFER_CAPACITY); +} + + +// Makes a new string buffer with specified capacity +StringBuf_t *allocate_SB(int capacity) { + + StringBuf_t *sbuf = allocate_BV(capacity); + setAppendOnly_BV(sbuf); + + return sbuf; +} + + +void ensureCapacity_SB(StringBuf_t *sBuf, int capacity) { + + ensureCapacity_BV(sBuf, capacity); +} + + +// Resets the given string buffer ... +void reset_SB(StringBuf_t *sBuf) { + reset_BV(sBuf); + setAppendOnly_BV(sBuf); +} + + +// Returns length of the string in the string-buffer +size_t length_SB(StringBuf_t *sBuf) { + return strlen(getContent(sBuf)); +} + + +// Prints string buffer content to stdout +void print_SB(StringBuf_t *sBuf) { + printf("%s", getContent(sBuf)); + fflush(stdout); +} + + +// Prints string buffer content to FILE stream +int fprint_SB(FILE *stream, StringBuf_t *sBuf) { + int status = fprintf(stream, "%s", getContent(sBuf)); + fflush(stream); + return status; +} + + +// Prints string buffer content into given string ... +int sprint_SB(char *buf, StringBuf_t *sBuf) { + return sprintf(buf, "%s", getContent(sBuf)); +} + +static char addItems_buffer[MSG_BUFSIZE+1]; + +// flexible means to add formatted data content to string buffer +void addItems_SB(StringBuf_t *dest, const char *fmt, ...) { + va_list args; + + va_start(args, fmt); + vsprintf(addItems_buffer, fmt, args); + va_end(args); + + addString_SB(dest, addItems_buffer); +} + +// Appends content from string buffer to string buffer +void addBuffer_SB(StringBuf_t *dest, StringBuf_t *source) { + appendInto_BV(dest, source); +} + + +// Appends content to string buffer +void addInt_SB(StringBuf_t *dest, int i) { + addItems_SB(dest, "%i", i); +} + +void addLong_SB(StringBuf_t *dest, long li) { + addItems_SB(dest, "%li", li); +} + +void addUInt_SB(StringBuf_t *dest, unsigned int ui) { + addItems_SB(dest, "%u", ui); +} + +void addULong_SB(StringBuf_t *dest, unsigned long ul) { + addItems_SB(dest, "%lu", ul); +} + +void addPtr_SB(StringBuf_t *dest, void *ptr) { + addItems_SB(dest, "%p", ptr); +} + +void addReal_SB(StringBuf_t *dest, double d) { + addItems_SB(dest, "%g", d); +} + +void addString_SB(StringBuf_t *dest, char *str) { + appendContent_BV(dest, strlen(str), (Byte_t *)str); +} + + +// Appends formatted content to string buffer +void addIntF_SB(StringBuf_t *dest, const char *fmt, int i) { + addItems_SB(dest, fmt, i); +} + +void addLongF_SB(StringBuf_t *dest, const char *fmt, long li) { + addItems_SB(dest, fmt, li); +} + +void addUIntF_SB(StringBuf_t *dest, const char *fmt, unsigned int ui) { + addItems_SB(dest, fmt, ui); +} + +void addULongF_SB(StringBuf_t *dest, const char *fmt, unsigned long ul) { + addItems_SB(dest, fmt, ul); +} + +void addPtrF_SB(StringBuf_t *dest, const char *fmt, void *ptr) { + addItems_SB(dest, fmt, ptr); +} + +void addRealF_SB(StringBuf_t *dest, const char *fmt, double d) { + addItems_SB(dest, fmt, d); +} + +void addStringF_SB(StringBuf_t *dest, const char *fmt, char *str) { + addItems_SB(dest, fmt, str); +} diff --git a/hash_fusion/lib/stringbuffer.h b/hash_fusion/lib/stringbuffer.h new file mode 100644 index 0000000000..f049c3c9e8 --- /dev/null +++ b/hash_fusion/lib/stringbuffer.h @@ -0,0 +1,116 @@ +#ifndef __STRINGBUFFER_H__ +#define __STRINGBUFFER_H__ + +#include <stdio.h> +#include "utils.h" +#include "bytevector.h" + +/******************************************************************************* + stringbuffer.h + + String Buffers (i.e. a kind of bytevector) + + - Convenient way to build strings. + - Appends content + + Author: brian.monahan@hpe.com + + (c) Copyright 2017 Hewlett Packard Enterprise Development LP + + 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. + + 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. +*******************************************************************************/ + +typedef ByteVec_t StringBuf_t; + +#define DEFAULT_STRINGBUFFER_CAPACITY 32 + + +// New string buffer with default capacity +StringBuf_t *new_SB(); + +// Makes a new string buffer with (at least) specified capacity +StringBuf_t *allocate_SB(int capacity); + +// Resets the given string buffer ... +void reset_SB(StringBuf_t *sBuf); + +// Ensure capacity of given stringbuffer ... +void ensureCapacity_SB(StringBuf_t *sBuf, int capacity); + +// Returns length of the string in the string-buffer +size_t length_SB(StringBuf_t *sBuf); + +// Prints string buffer content to stdout +void print_SB(StringBuf_t *sBuf); + +// Prints string buffer content to FILE stream +int fprint_SB(FILE *stream, StringBuf_t *sBuf); + +// Prints string buffer content into given string ... +int sprint_SB(char *buf, StringBuf_t *sBuf); + +// Flexible means to add formatted data content to string buffer +void addItems_SB(StringBuf_t *sBuf, const char *fmt, ...); + +// Appends content from string buffer to string buffer +void addBuffer_SB(StringBuf_t *dest, StringBuf_t *source); + + +// Appends content to string buffer +void addInt_SB(StringBuf_t *dest, int i); + +void addLong_SB(StringBuf_t *dest, long li); + +void addUInt_SB(StringBuf_t *dest, unsigned int ui); + +void addULong_SB(StringBuf_t *dest, unsigned long ul); + +void addPtr_SB(StringBuf_t *dest, void *ptr); + +void addReal_SB(StringBuf_t *dest, double d); + +void addString_SB(StringBuf_t *dest, char *str); + + +// Appends formatted content to string buffer +void addIntF_SB(StringBuf_t *dest, const char *fmt, int i); + +void addLongF_SB(StringBuf_t *dest, const char *fmt, long li); + +void addUIntF_SB(StringBuf_t *dest, const char *fmt, unsigned int ui); + +void addULongF_SB(StringBuf_t *dest, const char *fmt, unsigned long ul); + +void addPtrF_SB(StringBuf_t *dest, const char *fmt, void *ptr); + +void addRealF_SB(StringBuf_t *dest, const char *fmt, double d); + +void addStringF_SB(StringBuf_t *dest, const char *fmt, char *str); + + +// Defining Error Message for string buffers ... +#define error_exit_SB(sBuf) { diagnostic("%s", (char *)getContent_BV(sBuf)); error_exit(); } +#define codeError_exit_SB(sBuf) { diagnostic("%s", (char *)getContent_BV(sBuf)); codeError_exit(); } + +#endif diff --git a/hash_fusion/lib/testLib.c b/hash_fusion/lib/testLib.c new file mode 100644 index 0000000000..c6ab4fbc49 --- /dev/null +++ b/hash_fusion/lib/testLib.c @@ -0,0 +1,258 @@ +/* + Test Lib code: + + Hash Fusion and Merkle Tree testing code + + Author: brian.monahan@hpe.com + + (c) Copyright 2017 Hewlett Packard Enterprise Development LP + + 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. + + 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. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "utils.h" +#include "bytevector.h" +#include "stringbuffer.h" +#include "matrix.h" +#include "random.h" +#include "alloc.h" +#include "hashlib.h" +#include "merkleTree.h" +#include "fragment.h" +#include "fragmentMap.h" +#include "hashFusion.h" +#include "testLib.h" + +/******************************************************************************* + Variables and Arrays +*******************************************************************************/ + +// permutation of dataBlocks indicating the order in which +// dataBlocks arrive at their destination ... +// - Setting this to NULL ensures that the identity perm is used. +int *destBlocksPerm = 0; + +// Total number of data blocks to be consumed. +int totalBlocks = 5; //20 * 1024; // number of dataBlocks + +// Blocksize +int blockSize = 1024; + +// specifies type of hash +HashSpec_t hSpec = HSP_SHA256; + +// autoClean option - for Merkle Tree +Boolean_t autoClean = FALSE; + +// Hash Fusion accumulation type +HFuseAccum_t accumKind = LINEAR_LIST_ACCUM_HF; + +static Byte_t **dataBlocks = NULL; + +static ByteVec_t *tempBV = NULL; + + +/******************************************************************************* + Key comparison predicate +*******************************************************************************/ +Comparison_t keyCompFn(Key_t keyA, Key_t keyB) { + return cmp_key(keyA, keyB); +} + + +/******************************************************************************* + Adjacency comparison predicate +*******************************************************************************/ +AdjData_t adjCompFn(Key_t keyA, Key_t keyB) { + if (keyA == NULL_KEY) return ADJACENCY_UNDEF; + if (keyB == NULL_KEY) return ADJACENCY_UNDEF; + + long vA = (long)keyA; + long vB = (long)keyB; + + if (vA + 1 == vB) return LESS_THAN_ADJACENT; + if (vA == vB + 1) return GREATER_THAN_ADJACENT; + + return (vA < vB ? LESS_THAN_NOT_ADJACENT : vA == vB ? ADJACENCY_EQUAL : GREATER_THAN_NOT_ADJACENT); +} + + +/******************************************************************************* + Methods +*******************************************************************************/ +void initialiseTestData() { + // checking allocation ... + checkAllocation_MM = TRUE; + checkDeallocation_MM = TRUE; + tempBV = allocate_BV(blockSize+1); + dataBlocks = ALLOC_ARR(totalBlocks, Byte_t *); + + // allocate the destBlocksPerm array + destBlocksPerm = ALLOC_ARR(totalBlocks, int); +} + +void populateBlocks() { + + Byte_t *curBlock = NULL; + for (int i = 0; i < totalBlocks; i++) { + + // allocate fresh block ... + curBlock = ALLOC_BLK(blockSize); + dataBlocks[i] = curBlock; + // fill curBlock with random data + for (int j = 0; j < blockSize; j++) { + curBlock[j] = nextRandom_BYTE(); + } + // Load data block into bytevector + importForeignContent_BV(tempBV, blockSize, curBlock); + + // reset temp bytevector + reset_BV(tempBV); + } +} + +void randomiseDestOrder() { + + int swop = 0; + int temp = 0; + // insert default identity permutation ... + for (int i = 0; i < totalBlocks; i++) { + destBlocksPerm[i] = i; + } + + // randomly permute elements by swopping ... + for (int i = 0; i < totalBlocks; i++) { + swop = nextRandom_Range(0, totalBlocks-1); + + // swop element destBlocksPerm[i] with destBlocksPerm[swop] + temp = destBlocksPerm[i]; + destBlocksPerm[i] = destBlocksPerm[swop]; + destBlocksPerm[swop] = temp; + } +} + +/******************************************************************************* + Calc Digests Methods +*******************************************************************************/ + +Digest_t *calcDigest_FusionStruct(int *destPerm) { + + // New HFuse structure + HFuse_t *hFuse = new_HF(keyCompFn, adjCompFn, accumKind, hSpec); + + Byte_t *curBlock = NULL; + + int posn = 0; + + for (int count = 0; count < totalBlocks; count++) { + + posn = (destPerm == NULL ? count : destPerm[count]); + + // Set the current block + curBlock = dataBlocks[posn]; + + // Load data block into bytevector + reset_BV(tempBV); + importForeignContent_BV(tempBV, blockSize, curBlock); + + // Add data to fusion struct + if (!addDataBlock_HF(hFuse, posn+1, tempBV)) { + diagnostic("calcDigest_FusionStruct : addDataBlock_HF FAILED! posn: %i", posn+1); + error_exit(); + } + } + + // Freshly allocated digest + Digest_t *digest = new_DG(hSpec); + + // Check complete ... + if (getState_HF(hFuse) == Complete_HFuseState) { + + if (!getDigest_HF(digest, hFuse)) { + diagnostic("calcDigest_FusionStruct : complete digest undefined for hFuse"); + codeError_exit(); + } + } + else { + diagnostic("calcDigest_FusionStruct: HashFusion structure state: %s\n ... FAILED", showState_HF(hFuse)); + codeError_exit(); + } + + // Deallocate hFuse + deallocate_HF(hFuse); + + return digest; +} + + +Digest_t *calcDigest_MerkleTree(int *destPerm) { + + // New Merkle Tree + MTree_t *mTree = allocate_MT(hSpec, autoClean); + + Byte_t *curBlock = NULL; + + int posn = 0; + + for (int count = 0; count < totalBlocks; count++) { + + posn = (destPerm == NULL ? count : destPerm[count]); + + // Set the current block + curBlock = dataBlocks[posn]; + + // Load data block into bytevector + reset_BV(tempBV); + importForeignContent_BV(tempBV, blockSize, curBlock); + + // add data to tree + addDataBlock_MT(mTree, posn+1, tempBV); + } + + Digest_t *topHash = new_DG(hSpec); + + // Finalise ... + if (finalise_MT(mTree)) { + + if (!getTopHash_MT(topHash, mTree)) { + diagnostic("calcDigest_MerkleTree : top hash digest undefined for mTree_src"); + codeError_exit(); + } + + } + else { + diagnostic("calcDigest_MerkleTree: Merkle Tree structure state: %s\n ... FAILED", showState_MT(mTree)); + codeError_exit(); + } + + // deallocate memory + deallocate_MT(mTree); + + return topHash; +} diff --git a/hash_fusion/lib/testLib.h b/hash_fusion/lib/testLib.h new file mode 100644 index 0000000000..bb6c2e0a9f --- /dev/null +++ b/hash_fusion/lib/testLib.h @@ -0,0 +1,104 @@ +#ifndef __TEST_LIB_H__ +#define __TEST_LIB_H__ + +/******************************************************************************* + testLib.h + + Test Lib code for Hash Fusion and Merkle Tree testing code + + Author: brian.monahan@hpe.com + + (c) Copyright 2017 Hewlett Packard Enterprise Development LP + + 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. + + 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. +*******************************************************************************/ + +#include "utils.h" +#include "hashlib.h" +#include "fragment.h" +#include "fragmentMap.h" +#include "hashFusion.h" + + +typedef enum { + CONSOLE_OUTPUT_KIND = 650, // Console output + CSV_OUTPUT_KIND, // CSV output + JSON_OUTPUT_KIND // JSON output + } + OutputKind_t; + + +/******************************************************************************* + Parameters + - These parameters allow user code to set/get entities. +*******************************************************************************/ + +// Generated permutation of dataBlocks simulating the order in which +// dataBlocks arrive at their destination ... +int *destBlocksPerm; + +// Total number of data blocks to be consumed. +int totalBlocks; + +// Blocksize +int blockSize; + +// Specifies type of hash +HashSpec_t hSpec; + +// autoClean option - for Merkle Tree +Boolean_t autoClean; + +// Hash Fusion accumulation type +HFuseAccum_t accumKind; + + +/******************************************************************************* + Key comparison predicate +*******************************************************************************/ +Comparison_t keyCompFn(Key_t keyA, Key_t keyB); + + +/******************************************************************************* + Adjacency comparison predicate +*******************************************************************************/ +AdjData_t adjCompFn(Key_t keyA, Key_t keyB); + + +/******************************************************************************* + Methods +*******************************************************************************/ +void initialiseTestData(); + +void populateBlocks(); + +void randomiseDestOrder(); + +// These execute hash accumulation computation +// - input is a destination permutation (as 0-based int array) +// - output is pointer to the generated digest ... +Digest_t *calcDigest_FusionStruct(int *destPerm); +Digest_t *calcDigest_MerkleTree(int *destPerm); + +#endif diff --git a/hash_fusion/lib/utils.c b/hash_fusion/lib/utils.c new file mode 100644 index 0000000000..26edf59af4 --- /dev/null +++ b/hash_fusion/lib/utils.c @@ -0,0 +1,567 @@ +/* utils.c + + Utilities code ... + + These are "typically" generic/general purpose - not requiring particular + bespoke structs/data structures. + + Author: brian.monahan@hpe.com + + (c) Copyright 2017 Hewlett Packard Enterprise Development LP + + 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. + + 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. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <string.h> +#include <time.h> + +#include "utils.h" + + +/******************************************************************************* + Expoentiation function +*******************************************************************************/ +long power(int base, int exp) { + if (base == 0) return 0; + + if (exp < 0) { + diagnostic("power : Exponent is negative."); + error_exit(); + } + + if (exp == 0) return 1; + + long result = 1; + long oldResult = 1; + + for (int i = 0; i < exp; i++) { + oldResult = result; + result *= base; + + if (result < oldResult) { + diagnostic("power : overflow detected for base=%i, exp=%i", base, exp); + error_exit(); + } + } + + return result; +} + +/******************************************************************************* + Comparison functions + - This makes sense for both signed and unsigned values +*******************************************************************************/ +Comparison_t cmp_char(char a, char b) { return CMP(a, b); } +Comparison_t cmp_byte(Byte_t a, Byte_t b) { return CMP(a, b); } + +Comparison_t cmp_key(Key_t a, Key_t b) { return CMP(a, b); } +Comparison_t cmp_posn(Posn_t a, Posn_t b) { return CMP(a, b); } + +Comparison_t cmp_int(int a, int b) { return CMP(a, b); } +Comparison_t cmp_long(long a, long b) { return CMP(a, b); } + +Comparison_t cmp_uint(int a, int b) { return CMP(a, b); } +Comparison_t cmp_ulong(long a, long b) { return CMP(a, b); } + +Comparison_t cmp_float(float a, float b) { return CMP(a, b); } +Comparison_t cmp_double(double a, double b) { return CMP(a, b); } + +Comparison_t cmp_string(char *a, char *b) { return asComparison(strcmp(a, b)); } + + +/******************************************************************************* + Key-based maximum and minimum +*******************************************************************************/ +Key_t keyMax(CompareFn_t keyFn, Key_t keyA, Key_t keyB) { + return (keyFn(keyA, keyB) >= 0 ? keyA : keyB); +} + +Key_t keyMin(CompareFn_t keyFn, Key_t keyA, Key_t keyB) { + return (keyFn(keyA, keyB) <= 0 ? keyA : keyB); +} + + +/******************************************************************************* + Position-based maximum and minimum + - identical to keyMax/keyMin + - conceptually deals with positions not keys +*******************************************************************************/ +Posn_t posnMax(CompareFn_t posnFn, Posn_t posnA, Posn_t posnB) { + return (posnFn(posnA, posnB) >= 0 ? posnA : posnB); +} + +Posn_t posnMin(CompareFn_t posnFn, Posn_t posnA, Posn_t posnB) { + return (posnFn(posnA, posnB) <= 0 ? posnA : posnB); +} + + +/****************************************************************************** + Timing functions +******************************************************************************/ +static void nullFn() {} + +double timeFunction(int repeat, Thunk_t runFun) { + return timeFunction2(repeat, NULL, runFun); +} + +double timeFunction2(int repeat, Thunk_t setupFun, Thunk_t runFun) { + clock_t startTime, endTime = 0; + + int accumTicks = 0; + int overHead = 0; + int diffTime = 0; + + // Nothing to do + if (runFun == NULL) { + diagnostic("utils.timeFunction2: Null run function given - Nothing to measure!"); + error_exit(); + } + + Thunk_t setupFn = (setupFun == NULL ? nullFn : setupFun); + Thunk_t runFn = runFun; + + // timing loop + for(int i=0; i < repeat; i++) { + + // calling a null function + startTime = clock(); + nullFn(); + endTime = clock(); + overHead = (int)(endTime - startTime); + + // call set-up function + // - this part is NOT timed + setupFn(); + + // call actual function + startTime = clock(); + runFn(); + endTime = clock(); + + diffTime = (int)(endTime - startTime); + + // accum the internal time + accumTicks += max(0, diffTime - overHead); + } + + return (double)accumTicks/CLOCKS_PER_SEC; +} + + +/******************************************************************************* + Null functions +*******************************************************************************/ +// The null thunk closure +void nullThunk () {} + +// The null VoidFn that does nothing at all. +void nullVoidFn(void *obj) {} + + +/****************************************************************************** + printBytes - print a pure byte vector +******************************************************************************/ +void printHexBytes(Byte_t *bytes, int len) { + for(int i = 0; i < len; i++) + printf("%02x", bytes[i]); +} + + +/****************************************************************************** + HexDump utils. +******************************************************************************/ + +// Local prototypes +static void hexdump_line(char *arr, int count, int size, int width); +static void tabchars(char ch, int count); + +// Dumps binary data in hex to stdout +void hexdump(void *data, int size, int width) +{ + // Check size sanity + if (size <= 0) + { + printf("hexdump : Bad size: %i", size); + exit(2); + } + + // Check width sanity + if (width <= 0) + { + printf("hexdump : Bad width: %i", width); + exit(2); + } + + // Allocate variables + char *arr = (char *)malloc(size); + Byte_t *ptr = (Byte_t *)data; // ptr is a byte pointer + int count = 0; + + // Copy data to array arr + for (int i = 0; i < size; i++) + { + arr[i] = *ptr; // copy current byte + ptr += 1; // move ptr to next byte + } + + int outWidth = sizeof(Byte_t *) + 3 + 3*width + 1 + 1*width; + tabchars('=', outWidth); + + // reset ptr to data + ptr = data; + + // write out each line of the hex dump + while (count < size) { + hexdump_line(arr, count, size, width); + count += width; + } + + tabchars('=', outWidth); + + // now free the storage ... + free((void *)arr); +} + +static void hexdump_line(char *arr, int count, int size, int width) { + int i, j; + unsigned int ch; + + // print current address ... + printf("Ox%08lx ", (unsigned long)arr); + + // Now dump each element in hex + for (i = 0; i < width; i++) { + j = count + i; + if (j < size) + { + printf("%02x ", (unsigned char)arr[j]); + } + else + { + printf(" "); + } + } + + // Now finally dump each element as a (printable) char + for (i = 0; i < width; i++) + { + j = count + i; + if (j < size) + + { + ch = arr[j]; + if (ch >= ' ' && ch < 127) + { + printf("%c", (char)ch); + } + else + { + printf("."); + } + } + else + { + printf(" "); + } + } +} + + +// Dumps string of chars to stdout +// - ch = char to be dumped out +// - count = number of chars to be dumped out +static void tabchars(char ch, int count) { + int i = 0; + for (i = 0; i < count; i++) + { + printf("%c", ch); + } +} + + +/****************************************************************************** + Basic string processing + - generally update-in-place +******************************************************************************/ +void toLowerCase(char *text) { + if (text == NULL) return; + + for (char *p = text; *p != 0; p++) + *p = tolower(*p); + + /* + char lower = ('a' - 'A'); + + for (char *p = text; *p != 0; p++) { + if ('A' <= *p && *p <= 'Z') *p += lower; + } + + + char ch; + for (char i = 0; (ch = text[i]) != 0; i++) { + //printf("%i. Char: '%c' (0x%x)\n", i, ch, (int)ch); + if ('A' <= ch && ch <= 'Z') { + text[i] += lower; + } + } + */ +} + +void toUpperCase(char *text) { + if (text == NULL) return; + + for (char *p = text; *p != 0; p++) + *p = toupper(*p); +} + +void rightTrim(char *text) { + if (text == NULL) return; + + for (int i = strlen(text)-1; i >= 0; i--) { + if (isspace(text[i])) text[i] = 0; + else + break; + } +} + +char *leftTrim(char *text) { + if (text == NULL) return NULL; + + char *p = text; + + while (*p != 0) { + if (!isspace(*p)) return p; + p++; + } + + return p; +} + +char *trim(char *text) { + rightTrim(text); + return leftTrim(text); +} + +/****************************************************************************** + Reading and Writing Files to/from an array of blocks +******************************************************************************/ + +// readFile - takes a filename and reads it into a sequence of blocks +size_t readFile(const char *filename, Byte_t *blocks[], int maxBlocks) +{ + // initialise blocks + for (int i = 0; i<maxBlocks; i++) { + blocks[i] = NULL; + } + + FILE *ifp = fopen(filename,"r"); + if (ifp == NULL) { + diagnostic("Can't read file: %s", filename); + codeError_exit(); + } + + size_t totalCharsRead = 0; + size_t thisRead = 0; + void *blockPtr = NULL; + + for (int posn = 0; posn < maxBlocks && !feof(ifp); posn++) { + blockPtr = ALLOC_BLK(BLOCKSIZE); + thisRead = fread(blockPtr, 1, BLOCKSIZE, ifp); + blocks[posn] = blockPtr; + totalCharsRead += thisRead; + } + + fclose(ifp); + + return totalCharsRead; +} + + +// writeFile - takes a destination filename and write a sequence of blocks to it +void writeFile(const char *destFilename, int numChars, Byte_t *blocks[], int maxBlocks) +{ + // count the number of non-null blocks + int totalBlocks = 0; + for (int i = 0; i < maxBlocks; i++) { + if (blocks[i] != NULL) { + totalBlocks++; + } + } + + // open the output file for writing + FILE *ofp = fopen(destFilename,"w"); + if (ofp == NULL) { + diagnostic("Output file exists: %s", destFilename); + codeError_exit(); + } + + size_t charsRemaining = numChars; + size_t thisWrite = 0; + void *blockPtr = NULL; // current ptr to data block + + // write all blocks + for (int posn = 0; posn < totalBlocks && charsRemaining > 0; posn++) { + blockPtr = (void *)blocks[posn]; + thisWrite = (charsRemaining <= BLOCKSIZE ? charsRemaining : BLOCKSIZE); + thisWrite = fwrite(blockPtr, 1, thisWrite, ofp); + charsRemaining -= thisWrite; + } + + fflush(ofp); + fclose(ofp); +} + + +/****************************************************************************** + Assert statement + -- either failStop (i.e. exit on failure of check) + -- or soft warning (i.e. print message and continue on failure of check) +******************************************************************************/ +void __ASSERT(char *errMsg, int condition, char *fileName, int lineNum, Boolean_t doExit) { + if (condition == 0) { + // condition is FALSE + + // Ensure non-NULL errMsg + errMsg = (errMsg == NULL ? "" : errMsg); + + if (doExit) { + // issue ASSERT failed message and then exits ... + fprintf(stderr, "**** FAILED: check failed in file '%s' at line %i: %s ... exiting\n", fileName, lineNum, errMsg); + exit(1); + } + else { + // issue WARNING on message - and then continue ... + fprintf(stderr, "**** WARNING: check failed in file '%s' at line %i: %s\n", fileName, lineNum, errMsg); + } + } +} + + +/****************************************************************************** + Standard checks + __REQUIRES - always exits if check fails + __WARN_IF_NOT - doesn't exit if check fails +******************************************************************************/ +void __REQUIRES(char *msg, int condition, char *fileName, int lineNum) { + __ASSERT(msg, condition, fileName, lineNum, TRUE); +} + +void __WARN_IF_NOT(char *msg, int condition, char *fileName, int lineNum) { + __ASSERT(msg, condition, fileName, lineNum, FALSE); +} + + +/****************************************************************************** + Debugging ... + - to enable debugging, include the header "debug.h" +******************************************************************************/ +Boolean_t debugOn = FALSE; // Controls debugging output. Initially false. + +static int debugCount = DEBUG_LIMIT; + +void __DEBUG(const char *fmt, ...) { + if (! debugOn) return; + + fflush(stderr); // flush stderr + fflush(NULL); // flush all output + + va_list args; + + va_start(args, fmt); + + fprintf(stderr, ">>>> "); + vfprintf(stderr, fmt, args); + fprintf(stderr, "\n"); + + fflush(stderr); // flush stderr + fflush(NULL); // flush all output + + va_end(args); + + if (debugCount <= 0) { + diagnostic("\n\n DEBUG LIMIT (%i) EXCEEDED : Loop found??", DEBUG_LIMIT); + error_exit(); + } + + debugCount--; +} + +void __XDEBUG(const char *fmt, ...) { +} + +static char __posnBuffer[LINE_BUFSIZE+1]; +char *__POSITION(char *filename, int linenumber) { + if (filename == NULL) { + + if (linenumber < 0) { + // filename == NULL && line < 0 + return ""; + + } else { + + // filename == NULL && line >= 0 + sprintf(__posnBuffer, "line %i", linenumber); + return __posnBuffer; + } + } else { + + if (linenumber < 0) { + // filename != NULL && line < 0 + return filename; + + } else { + + // filename != NULL && line >= 0 + sprintf(__posnBuffer, "[%s, line %i]", filename, linenumber); + return __posnBuffer; + } + } +} + + +/****************************************************************************** + Error processing +******************************************************************************/ +static char __errBuf[MSG_BUFSIZE+1]; + +void diagnostic(const char *fmt, ...) { + va_list args; + + va_start(args, fmt); + vsprintf(__errBuf, fmt, args); + va_end(args); +} + +void __ERROR() { + printf("**** %s\n", __errBuf); + exit(EXIT_FAILURE); +} + +void __CODE_ERROR(char *fileName, int lineNum) { + printf("**** CODE ERROR in file %s at line %i: %s\n", fileName, lineNum, __errBuf); + exit(EXIT_FAILURE); +} diff --git a/hash_fusion/lib/utils.h b/hash_fusion/lib/utils.h new file mode 100644 index 0000000000..b3aabd52bd --- /dev/null +++ b/hash_fusion/lib/utils.h @@ -0,0 +1,749 @@ +#ifndef __UTILS_H__ +#define __UTILS_H__ + +/******************************************************************************* + utils.h + + Utilities header + + Author: brian.monahan@hpe.com + + (c) Copyright 2017 Hewlett Packard Enterprise Development LP + + 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. + + 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. +*******************************************************************************/ +#include "options.h" // Various application specific options +#include <string.h> // Memory functions e.g. memset +#include <stdarg.h> // Variadic args ... +#include <stdint.h> // Standard int sizes (C99) + + +/******************************************************************************* + Enabling/disabling standard checks + + - The checks (i.e. req_..., needs_...) are described later (see below) + + - Useful for testing/ensuring correct behaviour. + + - They can all be enabled/disabled. + + - Because they may not be enabled, any essential checks must be made explicit. + +*******************************************************************************/ +// Comment out the following line to enable requires checking i.e. req_... +//#define SUPPRESS_REQUIRES_CHECKING + +// Comment out the following line to enable needs checking i,e, needs_... +//#define SUPPRESS_NEEDS_CHECKING + + +/******************************************************************************* + Standard sizes +*******************************************************************************/ +// standard file block size = 4k / 8k +//#define BLOCKSIZE (4 * 1024) +#define BLOCKSIZE (8 * 1024) + +// message/string buffer size +#define MSG_BUFSIZE (4 * LINE_BUFSIZE) + +// maximum line length +#define LINE_BUFSIZE STD_BUFSIZE +#define TEXT_BUFSIZE STD_BUFSIZE + +// Standard buffer size +#define STD_BUFSIZE 1024 + +// DEBUG_LIMIT defines the maximum number of debug messages output +// - useful for catching rogue loops +//#define DEBUG_LIMIT 1000 //default +#define DEBUG_LIMIT 1000 + + +/******************************************************************************* + Simple types: Bytes, Tags, Pointers, Keys and Booleans + + Keys are encoded as opaque values e.g. unsigned long. + +*******************************************************************************/ +//typedef unsigned char Byte_t; +typedef uint_fast8_t Byte_t; // Fastest implementation of 8-bit unsigned integers (C99) - typically it's unsigned char. +typedef Byte_t Boolean_t; // Boolean type + + +/******************************************************************************* + Opaque types: Pointers, Keys, Positions and Objects + + Pointers, Keys, Positions and Objects are encoded as opaque values e.g. unsigned long. + +*******************************************************************************/ +typedef unsigned long Opaque_t; // Standard opaque type +typedef Opaque_t Ptr_t; // Opque pointer handles (useful for debugging/printing). +typedef Opaque_t Key_t; // Opaque key handles. +typedef Opaque_t Posn_t; // Opaque position handles. +typedef Opaque_t Object_t; // Opaque object pointer handles. + +#define NULL_VAL 0 // Null opaque value + + +/******************************************************************************* + Tagged types + + Tag values are byte sized (i.e. 256 possible tag values) + + - Typically used to discriminate data structure variants. + e.g. struct treeNode { + Tag_t : tag; + ... + ... + }; + +*******************************************************************************/ +typedef Byte_t Tag_t; + +// tag value operators - requires tag field to be first byte of object/structure. +#define checkTag(objPtr, tagValue) (tagOf(objPtr) == (tagValue)) +#define tagOf(objPtr) (*((Tag_t *)objPtr)) + + +/******************************************************************************* + Misc. operators/constants +*******************************************************************************/ +// Standardised Boolean_t values +// - Only standardised boolean values can be compared for equality. +#define TRUE 1 +#define FALSE 0 + +// Some Boolean synonyms +#define YES TRUE +#define NO FALSE + +#define DO TRUE +#define DONT FALSE + + +// makes general value into a standardised Boolean_t value +#define asBoolean(x) ((x) ? TRUE : FALSE) +#define showBoolean(x) ((x) ? "TRUE" : "FALSE") + +// Negation +#define not(x) ((x) ? FALSE : TRUE) + +// Max and min macros +#define max(a,b) ((a) > (b) ? (a) : (b)) +#define min(a,b) ((a) < (b) ? (a) : (b)) +#define minmax(lo, val, hi) ((val) < (lo) ? (lo) : ((hi) < (val) ? (hi) : (val))) + +// General int powers for exp >= 0; +// - result = 0 if base = 0 +long power(int base, int exp); + +// Powers of 2 +// pow2 : int->int +#define pow2(x) ((1 << (x))) + + +/******************************************************************************* + Function types + +*******************************************************************************/ +// Thunks - Pure function closures with no args and no results (i.e side-effects). +typedef void (*Thunk_t)(); + +// Void functions +// - Typically used as type for "finaliser" or "dealloc" functions (e.g. free) +typedef void (*VoidFn_t)(void * obj); + +// Predicate functions (single argument) +typedef Boolean_t (*PredFn_t)(void *obj); + +// Show functions (single argument) +typedef char *(*ShowFn_t)(void *obj); + + +/******************************************************************************* + Printing NULL + +*******************************************************************************/ +// This denotes a NULL value in output +#define NULL_STR "??" + + +/******************************************************************************* + Linear Comparisons +*******************************************************************************/ +// Comparison datatype +// - in C, enum types are indistinguishable from int +// - In this case, safer in practice to follow established convention. +typedef int Comparison_t; + +// Standard comparison values +#define LT -1 // a < b +#define EQ 0 // a == b +#define GT 1 // a > b + +// Comparison functions over "keys" ... +// - this is either direct comparisons with basic types (e.g. integers) or indirect comparisons with +// - This implements the "compare" protocol: +// LT if (a less than b); +// EQ if (a equals b); +// GT if (a greater than b) +typedef Comparison_t (*CompareFn_t)(Key_t a, Key_t b); + +// Simple conversion to conversion +#define asComparison(v) ((v) < 0 ? LT : (v) == 0 ? EQ : GT) + + +/******************************************************************************* + Numeric comparison functions + - This makes sense for both signed and unsigned values +*******************************************************************************/ +// Comparison result +Comparison_t cmp_char(char a, char b); +Comparison_t cmp_byte(Byte_t a, Byte_t b); + +Comparison_t cmp_key(Key_t a, Key_t b); // treats keys like pure unsigned long +Comparison_t cmp_posn(Posn_t a, Posn_t b); // treats positions like pure unsigned long + +Comparison_t cmp_int(int a, int b); +Comparison_t cmp_long(long a, long b); + +Comparison_t cmp_uint(int a, int b); +Comparison_t cmp_ulong(long a, long b); + +Comparison_t cmp_float(float a, float b); +Comparison_t cmp_double(double a, double b); + +Comparison_t cmp_string(char *a, char *b); + + +// Simple CMP macro - Comparison_tgr +// - Beware, this evaluates/expands arguments _twice_ +// This is fine if args are variables/literals, but not side-effecting expressions. +#define CMP(a, b) ((a) < (b) ? LT : (a) == (b) ? EQ : GT) + + +/******************************************************************************* + Key-based maximum and minimum +*******************************************************************************/ +Key_t keyMax(CompareFn_t keyFn, Key_t keyA, Key_t keyB); +Key_t keyMin(CompareFn_t keyFn, Key_t keyA, Key_t keyB); + + +/******************************************************************************* + Position-based maximum and minimum +*******************************************************************************/ +Posn_t posnMax(CompareFn_t posnFn, Posn_t posnA, Posn_t posnB); +Posn_t posnMin(CompareFn_t posnFn, Posn_t posnA, Posn_t posnB); + + +/******************************************************************************* + Key amd position values + + - These are typically opaque objects such as integers/longs or strings (i.e. pointers to char) + or pointers to some key data object. + + - The NULL_KEY and NULL_POSN value (i.e. 0) is specified as a "default" value (with application-specific semantics). + This value may or may not be meaningful. It can legitimately be used as a standard key or position value or + alternatively, as a "void", "invalid" or "non-key" value. Exactly how it is treated is considered + to be implementation specific/application defined. + + - When keys and positions are simple integers/longs, then we assume that + keys and positions are strictly positive and linearly ordered by <. + + - Otherwise, a key/position comparison function is required that implements a + linear less-than comparison ordering, using the compare protocol (see above) + + - Equal keys are typically specified exactly (as ==) - but can be used . + +*******************************************************************************/ +// The NULL_KEY and NULL_POSN values denotes a "default" key value. +#define NULL_KEY ZERO_VAL +#define NULL_POSN ZERO_VAL + +// Default opaque literal value +#define ZERO_VAL 0 + + +/******************************************************************************* + Primitive memory allocation and nullify object + - guaranteed zeroed allocation +*******************************************************************************/ +//#define MEMALLOC(a, b) (malloc((a) * (b))) +#define MEMALLOC(a, b) (calloc((a), (b))) +#define ALLOC_STR(len) ((char *)MEMALLOC((len)+1, 1)) +#define ALLOC_BLK(sz) ((void *)MEMALLOC((sz), 1)) + +#define ALLOC_OBJ(T) ((T *)MEMALLOC(1, sizeof(T))) +#define ALLOC_ARR(dim, T) ((T *)MEMALLOC((dim), sizeof(T))) + +// Nullify macros - obj is a pointer to object to be nullified, T is the structure type. +#define NULLIFY_OBJ(obj, T) { if ((obj) != NULL) memset((obj), 0x00, sizeof(T)); } +#define NULLIFY(obj, sz) { memset((obj), 0x00, (sz)); } + +// realloc considered unreliable ... (data corruption ??) ... +//#define REALLOC_BLK(ptr, sz) ((void *)realloc((ptr), (sz))) +//#define REALLOC_OBJ(ptr, T) ((T *)realloc((ptr), sizeof(T))) + + +/******************************************************************************* + Fast multiply for byte values +*******************************************************************************/ +// Fast Byte Multiply +//Byte_t byteMultiplyTable[256 * 256]; +//void setupByteMultiply(); // Initialises byteMultiplyTable. +//void gen_ByteMultiplyTable(); // Generates a C source file for byteMultiplyTable. + +//#define byteMult(x, y) (byteMultiplyTable[(((Byte_t) x)<<8) | ((Byte_t)y)]) + + +/******************************************************************************* + Timing functions +*******************************************************************************/ +double timeFunction(int repeat, Thunk_t runFun); + +// Run each runFun repeatedly, returning total time taken ... +// Only the run function runFun is timed ... +// The setupFun is performed on each loop - and is not timed ... +double timeFunction2(int repeat, Thunk_t setupFun, Thunk_t runFun); + + +/******************************************************************************* + Null functions +*******************************************************************************/ +// The null thunk closure +void nullThunk (); + +// The null VoidFn that does nothing at all. +void nullVoidFn(void *obj); + + +/******************************************************************************* + Hex data printing ... +*******************************************************************************/ +// prints hex bytes to stdout +void printHexBytes(Byte_t *bytes, int len); + +// prints hex dump of data to stdout +void hexdump(void *data, int size, int width); + + +/****************************************************************************** + Basic string processing + - generally update-in-place +******************************************************************************/ +void toLowerCase(char *text); +void toUpperCase(char *text); + +// Trims string +void rightTrim(char *text); // Removes space chars from the end. +char *leftTrim(char *text); // Returns left-trimmed string (no update to text made). +char *trim(char *text); // Returns left-right-trimmed string (may be shorter). + +/******************************************************************************* + Reading and writing files ... +*******************************************************************************/ +size_t readFile(const char *filename, Byte_t *blocks[], int maxBlocks); +void writeFile(const char *destFilename, int numChars, Byte_t *blocks[], int maxBlocks); + + +/******************************************************************************* + Error messages + + The pattern of use is: + + diagnostic(fmt, v1, v2, v3, ...); + error_exit(); + + or, with a coding error i.e. the "impossible" case: + + diagnostic(fmt, v1, v2, v3, ...); + codeError_exit(); + + + Note: Question: Why is the diagnostic function not an exiting function? + + Answer: It would have been nice to efficiently wrap everything into a + single call like this: + + void errorFn(const char *fmt, ...); + + and used like this: + + errorFn(fmt, v1, v2, v3, ...); + + But then it would be necessary to explicitly include __FILE__ and __LINE__ + variables literally in code to obtain information. To avoid this + clumbsiness, the error_exit() and codeError_exit() macros are defined + instead to wrap-up the usage of __FILE__ and __LINE__ to simplify their + usage. + + +*******************************************************************************/ + +// This sets the error message to be issued at exit ... +void diagnostic(const char *fmt, ...); + +//These macros provide error exits that display error messages defined by "diagnostic" +#define error_exit() { __ERROR(); exit(1); } +#define codeError_exit() { __CODE_ERROR(__FILE__, __LINE__); exit(1); } + +void __ERROR(); +void __CODE_ERROR(char *fileName, int lineNum); + + +/******************************************************************************* + Debugging print statement ... + - Enable per file debugging by including "debug.h" + - To enable, the variable debugOn must also be set to TRUE. +*******************************************************************************/ + +#ifndef __DEBUG_H__ + + #undef debug + #undef xdebug + + #undef DEBUG_CODE + #undef XDEBUG_CODE + + #define debug __XDEBUG + #define xdebug __XDEBUG + + #ifndef DEBUG_LIMIT + #define DEBUG_LIMIT 1000 + #endif + +#endif + +Boolean_t debugOn; + +// Useful position markers ... (these are string values) +#define POSN (__POSITION(__FILE__ , __LINE__)) +#define LINE_POSN (__POSITION(NULL , __LINE__)) +#define FILE_POSN (__POSITION(__FILE__ , -1)) + +char *__POSITION(char *filename, int linenumber); + +void __DEBUG(const char *fmt, ...); +void __XDEBUG(const char *fmt, ...); + + +/******************************************************************************* + Asserts ... +*******************************************************************************/ + +#define ASSERT(msg, expr) { __ASSERT((msg), (expr), __FILE__, __LINE__, TRUE); } // exiting +#define WARN(msg, expr) { __ASSERT((msg), (expr), __FILE__, __LINE__, FALSE); } // non-exiting + +#define XASSERT(msg, expr) {} +#define XWARN(msg, expr) {} + +#undef NDEBUG // enable standard asserts ... + +// always permit standard asserts +#include <assert.h> + + +/******************************************************************************* + Standard conditions and checks + - these are always evaluated +*******************************************************************************/ +#define isa_Null(ptr) ((ptr) == NULL) +#define isa_NonNull(ptr) ((ptr) != NULL) + +#define isa_Same(ptr1, ptr2) ((ptr1) == (ptr2)) +#define isa_Distinct(ptr1, ptr2) ((ptr1) != (ptr2)) +#define isa_DistinctIfNonNull(ptr1, ptr2) ((ptr1) == NULL || (ptr2) == NULL || (ptr1) != (ptr2)) + +#define isa_EmptyStr(str) ((str) == NULL || strlen(str) == 0) +#define isa_NonEmptyStr(str) ((str) != NULL && strlen(str) > 0) + +#define isa_Pos(i) ((i) > 0) +#define isa_Neg(i) ((i) < 0) + +#define isa_PosZero(i) ((i) >= 0) +#define isa_NegZero(i) ((i) <= 0) + +#define isa_Zero(i) ((i) == 0) +#define isa_NonZero(i) ((i) != 0) + +#define is_EQ(i, j) ((i) == (j)) +#define is_NEQ(i, j) ((i) != (j)) + +#define is_LT(i, j) ((i) < (j)) +#define is_LE(i, j) ((i) <= (j)) + +#define is_NLT(i, j) ((i) >= (j)) +#define is_NLE(i, j) ((i) > (j)) + +#define is_GT(i, j) ((i) > (j)) +#define is_GE(i, j) ((i) >= (j)) + +#define is_NGT(i, j) ((i) <= (j)) +#define is_NGE(i, j) ((i) < (j)) + + +/******************************************************************************* + Standard pre-condition guards + + - There are several standard kind of check supported: + + - req_... = "requires ..." check (standard message, exits on failure, suppressable). + - needs_... = "needs ..." check (user-specified message, exits on failure, suppressable). + - ensure_... = "ensures ..." check. (user-specified message, exits on failure, not suppressable). + - warn_if_not_... = "warn if not ..." check. (user-specified message, does not exit , not suppressable). + +*******************************************************************************/ +#ifdef SUPPRESS_REQUIRES_CHECKING + + #define req_Null(ptr) {} + #define req_NonNull(ptr) {} + + #define req_Same(ptr1, ptr2) {} + #define req_Distinct(ptr1, ptr2) {} + #define req_DistinctIfNonNull(ptr1, ptr2) {} + + #define req_EmptyStr(str) {} + #define req_NonEmptyStr(str) {} + + #define req_Pos(i) {} + #define req_Neg(i) {} + + #define req_PosZero(i) {} + #define req_NegZero(i) {} + + #define req_Zero(i) {} + #define req_NonZero(i) {} + + #define req_EQ(i, j) {} + #define req_NEQ(i, j) {} + + #define req_LT(i, j) {} + #define req_LE(i, j) {} + + #define req_NLT(i, j) {} + #define req_NLE(i, j) {} + + #define req_GT(i, j) {} + #define req_GE(i, j) {} + + #define req_NGT(i, j) {} + #define req_NGE(i, j) {} + +#else + + #define req_Null(ptr) { needs_Null("Requires null pointer", (ptr)); } + #define req_NonNull(ptr) { needs_NonNull("Requires non-null pointer", (ptr)); } + + #define req_Same(ptr1, ptr2) { needs_Same("Requires same pointer", (ptr1), (ptr2)); } + #define req_Distinct(ptr1, ptr2) { needs_Distinct("Requires distinct pointers", (ptr1), (ptr2)); } + #define req_DistinctIfNonNull(ptr1, ptr2) { needs_DistinctIfNonNull("Requires distinct pointers when non-null", (ptr1), (ptr2)); } + + #define req_EmptyStr(str) { needs_EmptyStr("Requires empty string", (str)); } + #define req_NonEmptyStr(str) { needs_NonEmptyStr("Requires non-empty string", (str)); } + + #define req_Pos(i) { needs_Pos("Requires positive number", (i)); } + #define req_Neg(i) { needs_Neg("Requires negative number", (i)); } + + #define req_PosZero(i) { needs_PosZero("Requires positive or zero number", (i)); } + #define req_NegZero(i) { needs_NegZero("Requires negative or zero number", (i)); } + + #define req_Zero(i) { needs_Zero("Requires zero number", (i)); } + #define req_NonZero(i) { needs_NonZero("Requires non-zero number", (i)); } + + #define req_EQ(i, j) { needs_EQ("Requires equal numbers", (i), (j)); } + #define req_NEQ(i, j) { needs_NEQ("Requires unequal numbers", (i), (j)); } + + #define req_LT(i, j) { needs_LT("Requires less than (e.g. i < j)", (i), (j)); } + #define req_LE(i, j) { needs_LE("Requires less than or equal (e.g. i <= j)", (i), (j)); } + + #define req_NLT(i, j) { needs_NLT("Requires not less than (e.g. not i <= j)", (i), (j)); } + #define req_NLE(i, j) { needs_NLE("Requires not less than or equal (e.g. not i <= j)", (i), (j)); } + + #define req_GT(i, j) { needs_GT("Requires greater than (e.g. i > j)", (i), (j)); } + #define req_GE(i, j) { needs_GE("Requires greater than or equal (e.g. i >= j)", (i), (j)); } + + #define req_NGT(i, j) { needs_NGT("Requires not greater than (e.g. not i > j)", (i), (j)); } + #define req_NGE(i, j) { needs_NGE("Requires not greater than or equal (e.g. not i >= j)", (i), (j)); } + +#endif + +#ifdef SUPPRESS_NEEDS_CHECKING + + #define needs_Null(msg, ptr) {} + #define needs_NonNull(msg, ptr) {} + + #define needs_Same(msg, ptr1, ptr2) {} + #define needs_Distinct(msg, ptr1, ptr2) {} + #define needs_DistinctIfNonNull(msg, ptr1, ptr2) {} + + #define needs_EmptyStr(msg, str) {} + #define needs_NonEmptyStr(msg, str) {} + + #define needs_Pos(msg, i) {} + #define needs_Neg(msg, i) {} + + #define needs_PosZero(msg, i) {} + #define needs_NegZero(msg, i) {} + + #define needs_Zero(msg, i) {} + #define needs_NonZero(msg, i) {} + + #define needs_EQ(msg, i, j) {} + #define needs_NEQ(msg, i, j) {} + + #define needs_LT(msg, i, j) {} + #define needs_LE(msg, i, j) {} + + #define needs_NLT(msg, i, j) {} + #define needs_NLE(msg, i, j) {} + + #define needs_GT(msg, i, j) {} + #define needs_GE(msg, i, j) {} + + #define needs_NGT(msg, i, j) {} + #define needs_NGE(msg, i, j) {} + +#else + + #define needs_Null(msg, ptr) { __REQUIRES(msg, isa_Null(ptr), __FILE__, __LINE__); } + #define needs_NonNull(msg, ptr) { __REQUIRES(msg, isa_NonNull(ptr), __FILE__, __LINE__); } + + #define needs_Same(msg, ptr1, ptr2) { __REQUIRES(msg, isa_Same(ptr1, ptr2), __FILE__, __LINE__); } + #define needs_Distinct(msg, ptr1, ptr2) { __REQUIRES(msg, isa_Distinct(ptr1, ptr2), __FILE__, __LINE__); } + #define needs_DistinctIfNonNull(msg, ptr1, ptr2) { __REQUIRES(msg, isa_DistinctIfNonNull(ptr1, ptr2), __FILE__, __LINE__); } + + #define needs_EmptyStr(msg, str) { __REQUIRES(msg, isa_EmptyStr(str), __FILE__, __LINE__); } + #define needs_NonEmptyStr(msg, str) { __REQUIRES(msg, isa_NonEmptyStr(str), __FILE__, __LINE__); } + + #define needs_Pos(msg, i) { __REQUIRES(msg, isa_Pos(i), __FILE__, __LINE__); } + #define needs_Neg(msg, i) { __REQUIRES(msg, isa_Neg(i), __FILE__, __LINE__); } + + #define needs_PosZero(msg, i) { __REQUIRES(msg, isa_PosZero(i), __FILE__, __LINE__); } + #define needs_NegZero(msg, i) { __REQUIRES(msg, isa_NegZero(i), __FILE__, __LINE__); } + + #define needs_Zero(msg, i) { __REQUIRES(msg, isa_Zero(i), __FILE__, __LINE__); } + #define needs_NonZero(msg, i) { __REQUIRES(msg, isa_NonZero(i), __FILE__, __LINE__); } + + #define needs_EQ(msg, i, j) { __REQUIRES(msg, is_EQ(i, j), __FILE__, __LINE__); } + #define needs_NEQ(msg, i, j) { __REQUIRES(msg, is_NEQ(i, j), __FILE__, __LINE__); } + + #define needs_LT(msg, i, j) { __REQUIRES(msg, is_LT(i, j), __FILE__, __LINE__); } + #define needs_LE(msg, i, j) { __REQUIRES(msg, is_LE(i, j), __FILE__, __LINE__); } + + #define needs_NLT(msg, i, j) { __REQUIRES(msg, is_NLT(i, j), __FILE__, __LINE__); } + #define needs_NLE(msg, i, j) { __REQUIRES(msg, is_NLE(i, j), __FILE__, __LINE__); } + + #define needs_GT(msg, i, j) { __REQUIRES(msg, is_GT(i, j), __FILE__, __LINE__); } + #define needs_GE(msg, i, j) { __REQUIRES(msg, is_GE(i, j), __FILE__, __LINE__); } + + #define needs_NGT(msg, i, j) { __REQUIRES(msg, is_NGT(i, j), __FILE__, __LINE__); } + #define needs_NGE(msg, i, j) { __REQUIRES(msg, is_NGE(i, j), __FILE__, __LINE__); } + +#endif + +// ensure checks +#define ensure_Null(msg, ptr) { __REQUIRES(msg, isa_Null(ptr), __FILE__, __LINE__); } +#define ensure_NonNull(msg, ptr) { __REQUIRES(msg, isa_NonNull(ptr), __FILE__, __LINE__); } + +#define ensure_Same(msg, ptr1, ptr2) { __REQUIRES(msg, isa_Same(ptr1, ptr2), __FILE__, __LINE__); } +#define ensure_Distinct(msg, ptr1, ptr2) { __REQUIRES(msg, isa_Distinct(ptr1, ptr2), __FILE__, __LINE__); } +#define ensure_DistinctIfNonNull(msg, ptr1, ptr2) { __REQUIRES(msg, isa_DistinctIfNonNull(ptr1, ptr2), __FILE__, __LINE__); } + +#define ensure_EmptyStr(msg, str) { __REQUIRES(msg, isa_EmptyStr(str), __FILE__, __LINE__); } +#define ensure_NonEmptyStr(msg, str) { __REQUIRES(msg, isa_NonEmptyStr(str), __FILE__, __LINE__); } + +#define ensure_Pos(msg, i) { __REQUIRES(msg, isa_Pos(i), __FILE__, __LINE__); } +#define ensure_Neg(msg, i) { __REQUIRES(msg, isa_Neg(i), __FILE__, __LINE__); } + +#define ensure_PosZero(msg, i) { __REQUIRES(msg, isa_PosZero(i), __FILE__, __LINE__); } +#define ensure_NegZero(msg, i) { __REQUIRES(msg, isa_NegZero(i), __FILE__, __LINE__); } + +#define ensure_Zero(msg, i) { __REQUIRES(msg, isa_Zero(i), __FILE__, __LINE__); } +#define ensure_NonZero(msg, i) { __REQUIRES(msg, isa_NonZero(i), __FILE__, __LINE__); } + +#define ensure_EQ(msg, i, j) { __REQUIRES(msg, is_EQ(i, j), __FILE__, __LINE__); } +#define ensure_NEQ(msg, i, j) { __REQUIRES(msg, is_NEQ(i, j), __FILE__, __LINE__); } + +#define ensure_LT(msg, i, j) { __REQUIRES(msg, is_LT(i, j), __FILE__, __LINE__); } +#define ensure_LE(msg, i, j) { __REQUIRES(msg, is_LE(i, j), __FILE__, __LINE__); } + +#define ensure_NLT(msg, i, j) { __REQUIRES(msg, is_NLT(i, j), __FILE__, __LINE__); } +#define ensure_NLE(msg, i, j) { __REQUIRES(msg, is_NLE(i, j), __FILE__, __LINE__); } + +#define ensure_GT(msg, i, j) { __REQUIRES(msg, is_GT(i, j), __FILE__, __LINE__); } +#define ensure_GE(msg, i, j) { __REQUIRES(msg, is_GE(i, j), __FILE__, __LINE__); } + +#define ensure_NGT(msg, i, j) { __REQUIRES(msg, is_NGT(i, j), __FILE__, __LINE__); } +#define ensure_NGE(msg, i, j) { __REQUIRES(msg, is_NGE(i, j), __FILE__, __LINE__); } + +#define ensure(msg, pred) { __REQUIRES(msg, (pred), __FILE__, __LINE__); } +#define ensure_not(msg, pred) { __REQUIRES(msg, (!(pred)), __FILE__, __LINE__); } + +// WARNING checks +#define warn_if_not_Null(msg, ptr) { __WARN_IF_NOT(msg, isa_Null(ptr), __FILE__, __LINE__); } +#define warn_if_not_NonNull(msg, ptr) { __WARN_IF_NOT(msg, isa_NonNull(ptr), __FILE__, __LINE__); } + +#define warn_if_not_Same(msg, ptr1, ptr2) { __WARN_IF_NOT(msg, isa_Same(ptr1, ptr2), __FILE__, __LINE__); } +#define warn_if_not_Distinct(msg, ptr1, ptr2) { __WARN_IF_NOT(msg, isa_Distinct(ptr1, ptr2), __FILE__, __LINE__); } +#define warn_if_not_DistinctIfNonNull(msg, ptr1, ptr2) { __WARN_IF_NOT(msg, isa_DistinctIfNonNull(ptr1, ptr2), __FILE__, __LINE__); } + +#define warn_if_not_EmptyStr(msg, str) { __WARN_IF_NOT(msg, isa_EmptyStr(str), __FILE__, __LINE__); } +#define warn_if_not_NonEmptyStr(msg, str) { __WARN_IF_NOT(msg, isa_NonEmptyStr(str), __FILE__, __LINE__); } + +#define warn_if_not_Pos(msg, i) { __WARN_IF_NOT(msg, isa_Pos(i), __FILE__, __LINE__); } +#define warn_if_not_Neg(msg, i) { __WARN_IF_NOT(msg, isa_Neg(i), __FILE__, __LINE__); } + +#define warn_if_not_PosZero(msg, i) { __WARN_IF_NOT(msg, isa_PosZero(i), __FILE__, __LINE__); } +#define warn_if_not_NegZero(msg, i) { __WARN_IF_NOT(msg, isa_NegZero(i), __FILE__, __LINE__); } + +#define warn_if_not_Zero(msg, i) { __WARN_IF_NOT(msg, isa_Zero(i), __FILE__, __LINE__); } +#define warn_if_not_NonZero(msg, i) { __WARN_IF_NOT(msg, isa_NonZero(i), __FILE__, __LINE__); } + +#define warn_if_not_EQ(msg, i, j) { __WARN_IF_NOT(msg, is_EQ(i, j), __FILE__, __LINE__); } +#define warn_if_not_NEQ(msg, i, j) { __WARN_IF_NOT(msg, is_NEQ(i, j), __FILE__, __LINE__); } + +#define warn_if_not_LT(msg, i, j) { __WARN_IF_NOT(msg, is_LT(i, j), __FILE__, __LINE__); } +#define warn_if_not_LE(msg, i, j) { __WARN_IF_NOT(msg, is_LE(i, j), __FILE__, __LINE__); } + +#define warn_if_not_NLT(msg, i, j) { __WARN_IF_NOT(msg, is_NLT(i, j), __FILE__, __LINE__); } +#define warn_if_not_NLE(msg, i, j) { __WARN_IF_NOT(msg, is_NLE(i, j), __FILE__, __LINE__); } + +#define warn_if_not_GT(msg, i, j) { __WARN_IF_NOT(msg, is_GT(i, j), __FILE__, __LINE__); } +#define warn_if_not_GE(msg, i, j) { __WARN_IF_NOT(msg, is_GE(i, j), __FILE__, __LINE__); } + +#define warn_if_not_NGT(msg, i, j) { __WARN_IF_NOT(msg, is_NGT(i, j), __FILE__, __LINE__); } +#define warn_if_not_NGE(msg, i, j) { __WARN_IF_NOT(msg, is_NGE(i, j), __FILE__, __LINE__); } + +#define warn_if_not(msg, pred) { __WARN_IF_NOT(msg, (pred), __FILE__, __LINE__); } +#define warn_if(msg, pred) { __WARN_IF_NOT(msg, (!(pred)), __FILE__, __LINE__); } + + +// helper code signatures +void __REQUIRES(char *msg, int condition, char *fileName, int lineNum); // always exits +void __WARN_IF_NOT(char *msg, int condition, char *fileName, int lineNum); // doesn't exit +void __ASSERT(char *errMsg, int condition, char *fileName, int lineNum, Boolean_t doExit); + + +#endif diff --git a/monero_crypto/CMakeLists.txt b/monero_crypto/CMakeLists.txt new file mode 100644 index 0000000000..1662c77c62 --- /dev/null +++ b/monero_crypto/CMakeLists.txt @@ -0,0 +1,404 @@ +# Copyright (c) 2014-2017, The Monero Project +# Copyright (c) 2018, DapCash 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. + +project (monero_crypto) + +# ARCH defines the target architecture, either by an explicit identifier or +# one of the following two keywords. By default, ARCH a value of 'native': +# target arch = host arch, binary is not portable. When ARCH is set to the +# string 'default', no -march arg is passed, which creates a binary that is +# portable across processors in the same family as host processor. In cases +# when ARCH is not set to an explicit identifier, cmake's builtin is used +# to identify the target architecture, to direct logic in this cmake script. +# Since ARCH is a cached variable, it will not be set on first cmake invocation. +set(STATIC 1) + +if (NOT ARCH OR ARCH STREQUAL "" OR ARCH STREQUAL "native" OR ARCH STREQUAL "default") + set(ARCH_ID "${CMAKE_SYSTEM_PROCESSOR}") +else() + set(ARCH_ID "${ARCH}") +endif() +string(TOLOWER "${ARCH_ID}" ARM_ID) +string(SUBSTRING "${ARM_ID}" 0 3 ARM_TEST) +if (ARM_TEST STREQUAL "arm") + set(ARM 1) + string(SUBSTRING "${ARM_ID}" 0 5 ARM_TEST) + if (ARM_TEST STREQUAL "armv6") + set(ARM6 1) + endif() + if (ARM_TEST STREQUAL "armv7") + set(ARM7 1) + endif() +endif() + +if (ARM_ID STREQUAL "aarch64" OR ARM_ID STREQUAL "arm64" OR ARM_ID STREQUAL "armv8-a") + set(ARM 1) + set(ARM8 1) + set(ARCH "armv8-a") +endif() + +if(ARCH_ID STREQUAL "ppc64le") + set(PPC64LE 1) +endif() + +if(WIN32 OR ARM) + set(OPT_FLAGS_RELEASE "-O2") +else() + set(OPT_FLAGS_RELEASE "-Ofast") +endif() + +# Check whether we're on a 32-bit or 64-bit system +if(CMAKE_SIZEOF_VOID_P EQUAL "8") + set(DEFAULT_BUILD_64 ON) +else() + set(DEFAULT_BUILD_64 OFF) +endif() +option(BUILD_64 "Build for 64-bit? 'OFF' builds for 32-bit." ${DEFAULT_BUILD_64}) + +if(BUILD_64) + set(ARCH_WIDTH "64") +else() + set(ARCH_WIDTH "32") +endif() +message(STATUS "Building for a ${ARCH_WIDTH}-bit system") + +# Check if we're on FreeBSD so we can exclude the local miniupnpc (it should be installed from ports instead) +# CMAKE_SYSTEM_NAME checks are commonly known, but specifically taken from libsdl's CMakeLists +if(CMAKE_SYSTEM_NAME MATCHES "kFreeBSD.*|FreeBSD") + set(FREEBSD TRUE) +endif() + +# Check if we're on DragonFly BSD. See the README.md for build instructions. +if(CMAKE_SYSTEM_NAME MATCHES "DragonFly.*") + set(DRAGONFLY TRUE) +endif() + +# Check if we're on OpenBSD. See the README.md for build instructions. +if(CMAKE_SYSTEM_NAME MATCHES "kOpenBSD.*|OpenBSD.*") + set(OPENBSD TRUE) +endif() + +if(APPLE) + include_directories(SYSTEM /usr/include/malloc) + if(POLICY CMP0042) + cmake_policy(SET CMP0042 NEW) + endif() +endif() + +if(MSVC) + add_definitions("/bigobj /MP /W3 /GS- /D_CRT_SECURE_NO_WARNINGS /wd4996 /wd4345 /D_WIN32_WINNT=0x0600 /DWIN32_LEAN_AND_MEAN /DGTEST_HAS_TR1_TUPLE=0 /FIinline_c.h /D__SSE4_1__") + # set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Dinline=__inline") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /STACK:10485760") + foreach(VAR CMAKE_C_FLAGS_DEBUG CMAKE_CXX_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE CMAKE_CXX_FLAGS_RELEASE) + string(REPLACE "/MD" "/MT" ${VAR} "${${VAR}}") + endforeach() + include_directories(SYSTEM src/platform/msc) +else() + set(ARCH native CACHE STRING "CPU to build for: -march value or 'default' to not pass -march at all") + message(STATUS "Building on ${CMAKE_SYSTEM_PROCESSOR} for ${ARCH}") + if(ARCH STREQUAL "default") + set(ARCH_FLAG "") + elseif(PPC64LE) + set(ARCH_FLAG "-mcpu=${ARCH}") + elseif(IOS AND ARCH STREQUAL "arm64") + message(STATUS "IOS: Changing arch from arm64 to armv8") + set(ARCH_FLAG "-march=armv8") + else() + set(ARCH_FLAG "-march=${ARCH}") + endif() + set(WARNINGS "-Wall -Wextra -Wpointer-arith -Wundef -Wvla -Wwrite-strings -Wno-error=extra -Wno-error=deprecated-declarations -Wno-unused-parameter -Wno-unused-variable -W + no-error=unused-variable -Wno-error=undef -Wno-error=uninitialized") + if(NOT MINGW) + set(WARNINGS_AS_ERRORS_FLAG "-Werror") + endif() + if(CMAKE_C_COMPILER_ID STREQUAL "Clang") + if(ARM) + set(WARNINGS "${WARNINGS} -Wno-error=inline-asm") + endif() + else() + set(WARNINGS "${WARNINGS} -Wlogical-op -Wno-error=maybe-uninitialized -Wno-error=cpp") + endif() + if(MINGW) + set(WARNINGS "${WARNINGS} -Wno-error=unused-value -Wno-error=unused-but-set-variable") + set(MINGW_FLAG "${MINGW_FLAG} -DWIN32_LEAN_AND_MEAN") + set(Boost_THREADAPI win32) + include_directories(SYSTEM src/platform/mingw) + # mingw doesn't support LTO (multiple definition errors at link time) + set(USE_LTO_DEFAULT false) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--stack,10485760") + if(NOT BUILD_64) + add_definitions(-DWINVER=0x0501 -D_WIN32_WINNT=0x0501) + endif() + endif() + set(C_WARNINGS "-Waggregate-return -Wnested-externs -Wold-style-definition -Wstrict-prototypes") + set(CXX_WARNINGS "-Wno-reorder -Wno-missing-field-initializers") + + if(COVERAGE) + message(STATUS "Building with profiling for test coverage report") + set(COVERAGE_FLAGS "-fprofile-arcs -ftest-coverage --coverage") + endif() + + # With GCC 6.1.1 the compiled binary malfunctions due to aliasing. Until that + # is fixed in the code (Issue #847), force compiler to be conservative. + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-strict-aliasing") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-strict-aliasing") + + option(NO_AES "Explicitly disable AES support" ${NO_AES}) + + if(NO_AES) + message(STATUS "AES support explicitly disabled") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNO_AES") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNO_AES") + elseif(NOT ARM AND NOT PPC64LE) + message(STATUS "AES support enabled") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -maes") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes") + elseif(PPC64LE) + message(STATUS "AES support not available on ppc64le") + elseif(ARM6) + message(STATUS "AES support not available on ARMv6") + elseif(ARM7) + message(STATUS "AES support not available on ARMv7") + elseif(ARM8) + CHECK_CXX_ACCEPTS_FLAG("-march=${ARCH}+crypto" ARCH_PLUS_CRYPTO) + if(ARCH_PLUS_CRYPTO) + message(STATUS "Crypto extensions enabled for ARMv8") + set(ARCH_FLAG "-march=${ARCH}+crypto") + else() + message(STATUS "Crypto extensions unavailable on your ARMv8 device") + endif() + else() + message(STATUS "AES support disabled") + endif() + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_FLAG} ${WARNINGS} ${C_WARNINGS} ${ARCH_FLAG} ${COVERAGE_FLAGS} ${PIC_FLAG}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_CPP_FLAG} ${WARNINGS} ${CXX_WARNINGS} ${ARCH_FLAG} ${COVERAGE_FLAGS} ${PIC_FLAG}") + + # With GCC 6.1.1 the compiled binary malfunctions due to aliasing. Until that + # is fixed in the code (Issue #847), force compiler to be conservative. + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-strict-aliasing") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-strict-aliasing") + if(ARM) + message(STATUS "Setting FPU Flags for ARM Processors") + + #NB NEON hardware does not fully implement the IEEE 754 standard for floating-point arithmetic + #Need custom assembly code to take full advantage of NEON SIMD + + #Cortex-A5/9 -mfpu=neon-fp16 + #Cortex-A7/15 -mfpu=neon-vfpv4 + #Cortex-A8 -mfpu=neon + #ARMv8 -FP and SIMD on by default for all ARM8v-A series, NO -mfpu setting needed + + #For custom -mtune, processor IDs for ARMv8-A series: + #0xd04 - Cortex-A35 + #0xd07 - Cortex-A57 + #0xd08 - Cortex-A72 + #0xd03 - Cortex-A73 + + if(NOT ARM8) + CHECK_CXX_ACCEPTS_FLAG(-mfpu=vfp3-d16 CXX_ACCEPTS_VFP3_D16) + CHECK_CXX_ACCEPTS_FLAG(-mfpu=vfp4 CXX_ACCEPTS_VFP4) + CHECK_CXX_ACCEPTS_FLAG(-mfloat-abi=hard CXX_ACCEPTS_MFLOAT_HARD) + CHECK_CXX_ACCEPTS_FLAG(-mfloat-abi=softfp CXX_ACCEPTS_MFLOAT_SOFTFP) + endif() + + if(ARM8) + CHECK_CXX_ACCEPTS_FLAG(-mfix-cortex-a53-835769 CXX_ACCEPTS_MFIX_CORTEX_A53_835769) + CHECK_CXX_ACCEPTS_FLAG(-mfix-cortex-a53-843419 CXX_ACCEPTS_MFIX_CORTEX_A53_843419) + endif() + + if(ARM6) + message(STATUS "Selecting VFP for ARMv6") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpu=vfp") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpu=vfp") + endif(ARM6) + if(ARM7) + if(CXX_ACCEPTS_VFP3_D16 AND NOT CXX_ACCEPTS_VFP4) + message(STATUS "Selecting VFP3 for ARMv7") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpu=vfp3-d16") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpu=vfp3-d16") + endif() + + if(CXX_ACCEPTS_VFP4) + message(STATUS "Selecting VFP4 for ARMv7") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpu=vfp4") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpu=vfp4") + endif() + + if(CXX_ACCEPTS_MFLOAT_HARD) + message(STATUS "Setting Hardware ABI for Floating Point") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfloat-abi=hard") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfloat-abi=hard") + endif() + + if(CXX_ACCEPTS_MFLOAT_SOFTFP AND NOT CXX_ACCEPTS_MFLOAT_HARD) + message(STATUS "Setting Software ABI for Floating Point") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfloat-abi=softfp") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfloat-abi=softfp") + endif() + endif(ARM7) + if(ARM8) + if(CXX_ACCEPTS_MFIX_CORTEX_A53_835769) + message(STATUS "Enabling Cortex-A53 workaround 835769") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfix-cortex-a53-835769") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfix-cortex-a53-835769") + endif() + + if(CXX_ACCEPTS_MFIX_CORTEX_A53_843419) + message(STATUS "Enabling Cortex-A53 workaround 843419") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfix-cortex-a53-843419") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfix-cortex-a53-843419") + endif() + endif(ARM8) + + endif(ARM) + if(ANDROID AND NOT BUILD_GUI_DEPS STREQUAL "ON" OR IOS) + #From Android 5: "only position independent executables (PIE) are supported" + message(STATUS "Enabling PIE executable") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIE") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIE") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_CXX_FLAGS} -fPIE -pie") + endif() + + if(APPLE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGTEST_HAS_TR1_TUPLE=0") + endif() + + set(DEBUG_FLAGS "-g3") + if(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT (CMAKE_C_COMPILER_VERSION VERSION_LESS 4.8)) + set(DEBUG_FLAGS "${DEBUG_FLAGS} -Og ") + else() + set(DEBUG_FLAGS "${DEBUG_FLAGS} -O0 ") + endif() + + if(NOT DEFINED USE_LTO_DEFAULT) + set(USE_LTO_DEFAULT false) + endif() + set(USE_LTO ${USE_LTO_DEFAULT} CACHE BOOL "Use Link-Time Optimization (Release mode only)") + + if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + # There is a clang bug that does not allow to compile code that uses AES-NI intrinsics if -flto is enabled, so explicitly disable + set(USE_LTO false) + endif() + if(USE_LTO) + set(RELEASE_FLAGS "${RELEASE_FLAGS} -flto") + if(STATIC) + set(RELEASE_FLAGS "${RELEASE_FLAGS} -ffat-lto-objects") + endif() + # Since gcc 4.9 the LTO format is non-standard (slim), so we need the gcc-specific ar and ranlib binaries + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9.0) AND NOT OPENBSD AND NOT DRAGONFLY) + # When invoking cmake on distributions on which gcc's binaries are prefixed + # with an arch-specific triplet, the user must specify -DCHOST=<prefix> + if (DEFINED CHOST) + set(CMAKE_AR "${CHOST}-gcc-ar") + set(CMAKE_RANLIB "${CHOST}-gcc-ranlib") + else() + set(CMAKE_AR "gcc-ar") + set(CMAKE_RANLIB "gcc-ranlib") + endif() + endif() + endif() + + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${DEBUG_FLAGS}") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${DEBUG_FLAGS}") + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${RELEASE_FLAGS}") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${RELEASE_FLAGS}") +endif() + + + + + +set(monero_crypto_sources + aesb.c + blake256.c + chacha8.c + crypto-ops-data.c + crypto-ops.c + 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(monero_crypto_headers) + +set(monero_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) + + + +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() + + +add_library(${PROJECT_NAME} STATIC ${monero_crypto_sources}) + +set(${PROJECT_NAME}_DEFINITIONS CACHE INTERNAL "${PROJECT_NAME}: Definitions" FORCE) + +set(${PROJECT_NAME}_INCLUDE_DIRS ${PROJECT_SOURCE_DIR} CACHE INTERNAL "${PROJECT_NAME}: Include Directories" FORCE) + diff --git a/monero_crypto/aesb.c b/monero_crypto/aesb.c new file mode 100644 index 0000000000..5d57b8af4b --- /dev/null +++ b/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/monero_crypto/blake256.c b/monero_crypto/blake256.c new file mode 100644 index 0000000000..1e43f9c4d9 --- /dev/null +++ b/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/monero_crypto/blake256.h b/monero_crypto/blake256.h new file mode 100644 index 0000000000..921fcd2fd5 --- /dev/null +++ b/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/monero_crypto/chacha8.c b/monero_crypto/chacha8.c new file mode 100644 index 0000000000..df135af594 --- /dev/null +++ b/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/monero_crypto/chacha8.h b/monero_crypto/chacha8.h new file mode 100644 index 0000000000..dcbe6a933a --- /dev/null +++ b/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/monero_crypto/common/int-util.h b/monero_crypto/common/int-util.h new file mode 100644 index 0000000000..7cec571ad8 --- /dev/null +++ b/monero_crypto/common/int-util.h @@ -0,0 +1,249 @@ +// 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 <assert.h> +#include <stdbool.h> +#include <stdint.h> +#include <string.h> +#include <sys/param.h> + +#if defined(__ANDROID__) +#include <byteswap.h> +#endif + +#if defined(__sun) && defined(__SVR4) +#include <endian.h> +#endif + +#if defined(_MSC_VER) +#include <stdlib.h> + +static inline uint32_t rol32(uint32_t x, int r) { + static_assert(sizeof(uint32_t) == sizeof(unsigned int), "this code assumes 32-bit integers"); + return _rotl(x, r); +} + +static inline uint64_t rol64(uint64_t x, int r) { + return _rotl64(x, r); +} + +#else + +static inline uint32_t rol32(uint32_t x, int r) { + return (x << (r & 31)) | (x >> (-r & 31)); +} + +static inline uint64_t rol64(uint64_t x, int r) { + return (x << (r & 63)) | (x >> (-r & 63)); +} + +#endif + +static inline uint64_t hi_dword(uint64_t val) { + return val >> 32; +} + +static inline uint64_t lo_dword(uint64_t val) { + return val & 0xFFFFFFFF; +} + +static inline uint64_t mul128(uint64_t multiplier, uint64_t multiplicand, uint64_t* product_hi) { + // multiplier = ab = a * 2^32 + b + // multiplicand = cd = c * 2^32 + d + // ab * cd = a * c * 2^64 + (a * d + b * c) * 2^32 + b * d + uint64_t a = hi_dword(multiplier); + uint64_t b = lo_dword(multiplier); + uint64_t c = hi_dword(multiplicand); + uint64_t d = lo_dword(multiplicand); + + uint64_t ac = a * c; + uint64_t ad = a * d; + uint64_t bc = b * c; + uint64_t bd = b * d; + + uint64_t adbc = ad + bc; + uint64_t adbc_carry = adbc < ad ? 1 : 0; + + // multiplier * multiplicand = product_hi * 2^64 + product_lo + uint64_t product_lo = bd + (adbc << 32); + uint64_t product_lo_carry = product_lo < bd ? 1 : 0; + *product_hi = ac + (adbc >> 32) + (adbc_carry << 32) + product_lo_carry; + assert(ac <= *product_hi); + + return product_lo; +} + +static inline uint64_t div_with_reminder(uint64_t dividend, uint32_t divisor, uint32_t* remainder) { + dividend |= ((uint64_t)*remainder) << 32; + *remainder = dividend % divisor; + return dividend / divisor; +} + +// Long division with 2^32 base +static inline uint32_t div128_32(uint64_t dividend_hi, uint64_t dividend_lo, uint32_t divisor, uint64_t* quotient_hi, uint64_t* quotient_lo) { + uint64_t dividend_dwords[4]; + uint32_t remainder = 0; + + dividend_dwords[3] = hi_dword(dividend_hi); + dividend_dwords[2] = lo_dword(dividend_hi); + dividend_dwords[1] = hi_dword(dividend_lo); + dividend_dwords[0] = lo_dword(dividend_lo); + + *quotient_hi = div_with_reminder(dividend_dwords[3], divisor, &remainder) << 32; + *quotient_hi |= div_with_reminder(dividend_dwords[2], divisor, &remainder); + *quotient_lo = div_with_reminder(dividend_dwords[1], divisor, &remainder) << 32; + *quotient_lo |= div_with_reminder(dividend_dwords[0], divisor, &remainder); + + return remainder; +} + +#define IDENT32(x) ((uint32_t) (x)) +#define IDENT64(x) ((uint64_t) (x)) + +#define SWAP32(x) ((((uint32_t) (x) & 0x000000ff) << 24) | \ + (((uint32_t) (x) & 0x0000ff00) << 8) | \ + (((uint32_t) (x) & 0x00ff0000) >> 8) | \ + (((uint32_t) (x) & 0xff000000) >> 24)) +#define SWAP64(x) ((((uint64_t) (x) & 0x00000000000000ff) << 56) | \ + (((uint64_t) (x) & 0x000000000000ff00) << 40) | \ + (((uint64_t) (x) & 0x0000000000ff0000) << 24) | \ + (((uint64_t) (x) & 0x00000000ff000000) << 8) | \ + (((uint64_t) (x) & 0x000000ff00000000) >> 8) | \ + (((uint64_t) (x) & 0x0000ff0000000000) >> 24) | \ + (((uint64_t) (x) & 0x00ff000000000000) >> 40) | \ + (((uint64_t) (x) & 0xff00000000000000) >> 56)) + +static inline uint32_t ident32(uint32_t x) { return x; } +static inline uint64_t ident64(uint64_t x) { return x; } + +#ifndef __OpenBSD__ +# if defined(__ANDROID__) && defined(__swap32) && !defined(swap32) +# define swap32 __swap32 +# elif !defined(swap32) +static inline uint32_t swap32(uint32_t x) { + x = ((x & 0x00ff00ff) << 8) | ((x & 0xff00ff00) >> 8); + return (x << 16) | (x >> 16); +} +# endif +# if defined(__ANDROID__) && defined(__swap64) && !defined(swap64) +# define swap64 __swap64 +# elif !defined(swap64) +static inline uint64_t swap64(uint64_t x) { + x = ((x & 0x00ff00ff00ff00ff) << 8) | ((x & 0xff00ff00ff00ff00) >> 8); + x = ((x & 0x0000ffff0000ffff) << 16) | ((x & 0xffff0000ffff0000) >> 16); + return (x << 32) | (x >> 32); +} +# endif +#endif /* __OpenBSD__ */ + +#if defined(__GNUC__) +#define UNUSED __attribute__((unused)) +#else +#define UNUSED +#endif +static inline void mem_inplace_ident(void *mem UNUSED, size_t n UNUSED) { } +#undef UNUSED + +static inline void mem_inplace_swap32(void *mem, size_t n) { + size_t i; + for (i = 0; i < n; i++) { + ((uint32_t *) mem)[i] = swap32(((const uint32_t *) mem)[i]); + } +} +static inline void mem_inplace_swap64(void *mem, size_t n) { + size_t i; + for (i = 0; i < n; i++) { + ((uint64_t *) mem)[i] = swap64(((const uint64_t *) mem)[i]); + } +} + +static inline void memcpy_ident32(void *dst, const void *src, size_t n) { + memcpy(dst, src, 4 * n); +} +static inline void memcpy_ident64(void *dst, const void *src, size_t n) { + memcpy(dst, src, 8 * n); +} + +static inline void memcpy_swap32(void *dst, const void *src, size_t n) { + size_t i; + for (i = 0; i < n; i++) { + ((uint32_t *) dst)[i] = swap32(((const uint32_t *) src)[i]); + } +} +static inline void memcpy_swap64(void *dst, const void *src, size_t n) { + size_t i; + for (i = 0; i < n; i++) { + ((uint64_t *) dst)[i] = swap64(((const uint64_t *) src)[i]); + } +} + +#if !defined(BYTE_ORDER) || !defined(LITTLE_ENDIAN) || !defined(BIG_ENDIAN) +static_assert(false, "BYTE_ORDER is undefined. Perhaps, GNU extensions are not enabled"); +#endif + +#if BYTE_ORDER == LITTLE_ENDIAN +#define SWAP32LE IDENT32 +#define SWAP32BE SWAP32 +#define swap32le ident32 +#define swap32be swap32 +#define mem_inplace_swap32le mem_inplace_ident +#define mem_inplace_swap32be mem_inplace_swap32 +#define memcpy_swap32le memcpy_ident32 +#define memcpy_swap32be memcpy_swap32 +#define SWAP64LE IDENT64 +#define SWAP64BE SWAP64 +#define swap64le ident64 +#define swap64be swap64 +#define mem_inplace_swap64le mem_inplace_ident +#define mem_inplace_swap64be mem_inplace_swap64 +#define memcpy_swap64le memcpy_ident64 +#define memcpy_swap64be memcpy_swap64 +#endif + +#if BYTE_ORDER == BIG_ENDIAN +#define SWAP32BE IDENT32 +#define SWAP32LE SWAP32 +#define swap32be ident32 +#define swap32le swap32 +#define mem_inplace_swap32be mem_inplace_ident +#define mem_inplace_swap32le mem_inplace_swap32 +#define memcpy_swap32be memcpy_ident32 +#define memcpy_swap32le memcpy_swap32 +#define SWAP64BE IDENT64 +#define SWAP64LE SWAP64 +#define swap64be ident64 +#define swap64le swap64 +#define mem_inplace_swap64be mem_inplace_ident +#define mem_inplace_swap64le mem_inplace_swap64 +#define memcpy_swap64be memcpy_ident64 +#define memcpy_swap64le memcpy_swap64 +#endif diff --git a/monero_crypto/common/memwipe.c b/monero_crypto/common/memwipe.c new file mode 100644 index 0000000000..da7e9f3461 --- /dev/null +++ b/monero_crypto/common/memwipe.c @@ -0,0 +1,106 @@ +// Copyright (c) 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 Copyright (c) 2009-2015 The Bitcoin Core developers + +#define __STDC_WANT_LIB_EXT1__ 1 +#include <string.h> +#include <stdlib.h> +#ifdef HAVE_EXPLICIT_BZERO +#include <strings.h> +#endif +#include "memwipe.h" + +#if defined(_MSC_VER) +#define SCARECROW \ + __asm; +#else +#define SCARECROW \ + __asm__ __volatile__("" : : "r"(ptr) : "memory"); +#endif + +#ifdef HAVE_MEMSET_S + +void *memwipe(void *ptr, size_t n) +{ + if (memset_s(ptr, n, 0, n)) + { + abort(); + } + SCARECROW // might as well... + return ptr; +} + +#elif defined HAVE_EXPLICIT_BZERO + +void *memwipe(void *ptr, size_t n) +{ + explicit_bzero(ptr, n); + SCARECROW + return ptr; +} + +#else + +/* The memory_cleanse implementation is taken from Bitcoin */ + +/* Compilers have a bad habit of removing "superfluous" memset calls that + * are trying to zero memory. For example, when memset()ing a buffer and + * then free()ing it, the compiler might decide that the memset is + * unobservable and thus can be removed. + * + * Previously we used OpenSSL which tried to stop this by a) implementing + * memset in assembly on x86 and b) putting the function in its own file + * for other platforms. + * + * This change removes those tricks in favour of using asm directives to + * scare the compiler away. As best as our compiler folks can tell, this is + * sufficient and will continue to be so. + * + * Adam Langley <agl@google.com> + * Commit: ad1907fe73334d6c696c8539646c21b11178f20f + * BoringSSL (LICENSE: ISC) + */ +static void memory_cleanse(void *ptr, size_t len) +{ + memset(ptr, 0, len); + + /* As best as we can tell, this is sufficient to break any optimisations that + might try to eliminate "superfluous" memsets. If there's an easy way to + detect memset_s, it would be better to use that. */ + SCARECROW +} + +void *memwipe(void *ptr, size_t n) +{ + memory_cleanse(ptr, n); + SCARECROW + return ptr; +} + +#endif diff --git a/monero_crypto/common/memwipe.h b/monero_crypto/common/memwipe.h new file mode 100644 index 0000000000..46cd131f3d --- /dev/null +++ b/monero_crypto/common/memwipe.h @@ -0,0 +1,36 @@ +// Copyright (c) 2017, The Monero Project +// Copyrught (c) 2018, DapCash 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 _MEMWIPE_H_ +#define _MEMWIPE_H_ + +void *memwipe(void *src, size_t n); + +#endif \ No newline at end of file diff --git a/monero_crypto/crypto-ops-data.c b/monero_crypto/crypto-ops-data.c new file mode 100644 index 0000000000..4bd75b77c6 --- /dev/null +++ b/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/monero_crypto/crypto-ops.c b/monero_crypto/crypto-ops.c new file mode 100644 index 0000000000..b5c62bce43 --- /dev/null +++ b/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/monero_crypto/crypto-ops.h b/monero_crypto/crypto-ops.h new file mode 100644 index 0000000000..c764555517 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/Makefile b/monero_crypto/crypto_ops_builder/Makefile new file mode 100755 index 0000000000..69b0d3ba37 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/README.md b/monero_crypto/crypto_ops_builder/README.md new file mode 100644 index 0000000000..3b87966f53 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/api.h b/monero_crypto/crypto_ops_builder/api.h new file mode 100755 index 0000000000..60339596d9 --- /dev/null +++ b/monero_crypto/crypto_ops_builder/api.h @@ -0,0 +1,2 @@ +#define CRYPTO_BYTES 32 +#define CRYPTO_SCALARBYTES 32 diff --git a/monero_crypto/crypto_ops_builder/crypto-ops-data.c b/monero_crypto/crypto_ops_builder/crypto-ops-data.c new file mode 100644 index 0000000000..4bd75b77c6 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/crypto-ops-old.c b/monero_crypto/crypto_ops_builder/crypto-ops-old.c new file mode 100644 index 0000000000..b7a290b4ae --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/crypto-ops.h b/monero_crypto/crypto_ops_builder/crypto-ops.h new file mode 100644 index 0000000000..47d5b46aea --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/crypto_int32.h b/monero_crypto/crypto_ops_builder/crypto_int32.h new file mode 100755 index 0000000000..cae135e6e2 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/crypto_sign.h b/monero_crypto/crypto_ops_builder/crypto_sign.h new file mode 100755 index 0000000000..afed20821c --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/crypto_uint32.h b/monero_crypto/crypto_ops_builder/crypto_uint32.h new file mode 100755 index 0000000000..21020d7b57 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/crypto_verify_32.h b/monero_crypto/crypto_ops_builder/crypto_verify_32.h new file mode 100755 index 0000000000..ad265c7a3f --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ietf.txt b/monero_crypto/crypto_ops_builder/ietf.txt new file mode 100644 index 0000000000..0736f71ec0 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/include/Makefile.am b/monero_crypto/crypto_ops_builder/include/Makefile.am new file mode 100644 index 0000000000..894c371a37 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/include/libsodium_LICENSE b/monero_crypto/crypto_ops_builder/include/libsodium_LICENSE new file mode 100644 index 0000000000..3edb000f65 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/include/sodium.h b/monero_crypto/crypto_ops_builder/include/sodium.h new file mode 100644 index 0000000000..207bdedeb6 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/include/sodium/crypto_int32.h b/monero_crypto/crypto_ops_builder/include/sodium/crypto_int32.h new file mode 100644 index 0000000000..a22019d87c --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/include/sodium/crypto_int64.h b/monero_crypto/crypto_ops_builder/include/sodium/crypto_int64.h new file mode 100644 index 0000000000..f68a283611 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/include/sodium/crypto_uint16.h b/monero_crypto/crypto_ops_builder/include/sodium/crypto_uint16.h new file mode 100644 index 0000000000..6be4e347c6 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/include/sodium/crypto_uint32.h b/monero_crypto/crypto_ops_builder/include/sodium/crypto_uint32.h new file mode 100644 index 0000000000..ba66cecc65 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/include/sodium/crypto_uint64.h b/monero_crypto/crypto_ops_builder/include/sodium/crypto_uint64.h new file mode 100644 index 0000000000..98b3f6d344 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/include/sodium/crypto_uint8.h b/monero_crypto/crypto_ops_builder/include/sodium/crypto_uint8.h new file mode 100644 index 0000000000..789613ba5f --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/include/sodium/crypto_verify_32.h b/monero_crypto/crypto_ops_builder/include/sodium/crypto_verify_32.h new file mode 100644 index 0000000000..58e4d0e829 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/include/sodium/randombytes.h b/monero_crypto/crypto_ops_builder/include/sodium/randombytes.h new file mode 100644 index 0000000000..08aff05259 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/randombytes.c b/monero_crypto/crypto_ops_builder/randombytes.c new file mode 100755 index 0000000000..fa7d42149d --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/Makefile b/monero_crypto/crypto_ops_builder/ref10/Makefile new file mode 100644 index 0000000000..9b0ba7ad45 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/api.h b/monero_crypto/crypto_ops_builder/ref10/api.h new file mode 100644 index 0000000000..d88dae0c32 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/base.h b/monero_crypto/crypto_ops_builder/ref10/base.h new file mode 100644 index 0000000000..573bd8a05c --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/base.py b/monero_crypto/crypto_ops_builder/ref10/base.py new file mode 100644 index 0000000000..84accc8580 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/base2.h b/monero_crypto/crypto_ops_builder/ref10/base2.h new file mode 100644 index 0000000000..8c538440ff --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/base2.py b/monero_crypto/crypto_ops_builder/ref10/base2.py new file mode 100644 index 0000000000..5e4e8739d0 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/d.h b/monero_crypto/crypto_ops_builder/ref10/d.h new file mode 100644 index 0000000000..e25f578350 --- /dev/null +++ b/monero_crypto/crypto_ops_builder/ref10/d.h @@ -0,0 +1 @@ +-10913610,13857413,-15372611,6949391,114729,-8787816,-6275908,-3247719,-18696448,-12055116 diff --git a/monero_crypto/crypto_ops_builder/ref10/d.py b/monero_crypto/crypto_ops_builder/ref10/d.py new file mode 100644 index 0000000000..8995bb86a3 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/d2.h b/monero_crypto/crypto_ops_builder/ref10/d2.h new file mode 100644 index 0000000000..01aaec7512 --- /dev/null +++ b/monero_crypto/crypto_ops_builder/ref10/d2.h @@ -0,0 +1 @@ +-21827239,-5839606,-30745221,13898782,229458,15978800,-12551817,-6495438,29715968,9444199 diff --git a/monero_crypto/crypto_ops_builder/ref10/d2.py b/monero_crypto/crypto_ops_builder/ref10/d2.py new file mode 100644 index 0000000000..79841758be --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/description b/monero_crypto/crypto_ops_builder/ref10/description new file mode 100644 index 0000000000..cbfcb2cbaf --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/designers b/monero_crypto/crypto_ops_builder/ref10/designers new file mode 100644 index 0000000000..2a3a93a8ee --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/fe.h b/monero_crypto/crypto_ops_builder/ref10/fe.h new file mode 100644 index 0000000000..60c308ba46 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/fe_0.c b/monero_crypto/crypto_ops_builder/ref10/fe_0.c new file mode 100644 index 0000000000..ec879d7337 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/fe_1.c b/monero_crypto/crypto_ops_builder/ref10/fe_1.c new file mode 100644 index 0000000000..8cf7784844 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/fe_add.c b/monero_crypto/crypto_ops_builder/ref10/fe_add.c new file mode 100644 index 0000000000..e6a81da202 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/fe_cmov.c b/monero_crypto/crypto_ops_builder/ref10/fe_cmov.c new file mode 100644 index 0000000000..8ca584fb19 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/fe_copy.c b/monero_crypto/crypto_ops_builder/ref10/fe_copy.c new file mode 100644 index 0000000000..9c5bf865a2 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/fe_frombytes.c b/monero_crypto/crypto_ops_builder/ref10/fe_frombytes.c new file mode 100644 index 0000000000..5c17917487 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/fe_invert.c b/monero_crypto/crypto_ops_builder/ref10/fe_invert.c new file mode 100644 index 0000000000..bcfdb8ff87 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/fe_isnegative.c b/monero_crypto/crypto_ops_builder/ref10/fe_isnegative.c new file mode 100644 index 0000000000..3b2c8b8d52 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/fe_isnonzero.c b/monero_crypto/crypto_ops_builder/ref10/fe_isnonzero.c new file mode 100644 index 0000000000..47568001ce --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/fe_mul.c b/monero_crypto/crypto_ops_builder/ref10/fe_mul.c new file mode 100644 index 0000000000..26ca8b3682 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/fe_neg.c b/monero_crypto/crypto_ops_builder/ref10/fe_neg.c new file mode 100644 index 0000000000..2078ce5284 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/fe_pow22523.c b/monero_crypto/crypto_ops_builder/ref10/fe_pow22523.c new file mode 100644 index 0000000000..56675a5902 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/fe_sq.c b/monero_crypto/crypto_ops_builder/ref10/fe_sq.c new file mode 100644 index 0000000000..8dd119841c --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/fe_sq2.c b/monero_crypto/crypto_ops_builder/ref10/fe_sq2.c new file mode 100644 index 0000000000..026ed3aacf --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/fe_sub.c b/monero_crypto/crypto_ops_builder/ref10/fe_sub.c new file mode 100644 index 0000000000..6e26b7df8f --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/fe_tobytes.c b/monero_crypto/crypto_ops_builder/ref10/fe_tobytes.c new file mode 100644 index 0000000000..0a63baf9c1 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/ge.h b/monero_crypto/crypto_ops_builder/ref10/ge.h new file mode 100644 index 0000000000..55e95f95b6 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/ge_add.c b/monero_crypto/crypto_ops_builder/ref10/ge_add.c new file mode 100644 index 0000000000..da7ff5d2eb --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/ge_add.h b/monero_crypto/crypto_ops_builder/ref10/ge_add.h new file mode 100644 index 0000000000..7481f8ffbe --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/ge_add.q b/monero_crypto/crypto_ops_builder/ref10/ge_add.q new file mode 100644 index 0000000000..a6572ab0f8 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/ge_double_scalarmult.c b/monero_crypto/crypto_ops_builder/ref10/ge_double_scalarmult.c new file mode 100644 index 0000000000..f8bf4bf775 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/ge_frombytes.c b/monero_crypto/crypto_ops_builder/ref10/ge_frombytes.c new file mode 100644 index 0000000000..1a059ee93f --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/ge_madd.c b/monero_crypto/crypto_ops_builder/ref10/ge_madd.c new file mode 100644 index 0000000000..622571774b --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/ge_madd.h b/monero_crypto/crypto_ops_builder/ref10/ge_madd.h new file mode 100644 index 0000000000..ecae84952b --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/ge_madd.q b/monero_crypto/crypto_ops_builder/ref10/ge_madd.q new file mode 100644 index 0000000000..aa3db454e6 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/ge_msub.c b/monero_crypto/crypto_ops_builder/ref10/ge_msub.c new file mode 100644 index 0000000000..741ecbf113 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/ge_msub.h b/monero_crypto/crypto_ops_builder/ref10/ge_msub.h new file mode 100644 index 0000000000..500f986ba0 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/ge_msub.q b/monero_crypto/crypto_ops_builder/ref10/ge_msub.q new file mode 100644 index 0000000000..e3cadd882d --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/ge_p1p1_to_p2.c b/monero_crypto/crypto_ops_builder/ref10/ge_p1p1_to_p2.c new file mode 100644 index 0000000000..9bb5013d66 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/ge_p1p1_to_p3.c b/monero_crypto/crypto_ops_builder/ref10/ge_p1p1_to_p3.c new file mode 100644 index 0000000000..2f57b10968 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/ge_p2_0.c b/monero_crypto/crypto_ops_builder/ref10/ge_p2_0.c new file mode 100644 index 0000000000..6191d1e6e4 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/ge_p2_dbl.c b/monero_crypto/crypto_ops_builder/ref10/ge_p2_dbl.c new file mode 100644 index 0000000000..2e332b5cee --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/ge_p2_dbl.h b/monero_crypto/crypto_ops_builder/ref10/ge_p2_dbl.h new file mode 100644 index 0000000000..128efed907 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/ge_p2_dbl.q b/monero_crypto/crypto_ops_builder/ref10/ge_p2_dbl.q new file mode 100644 index 0000000000..170d42f9a7 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/ge_p3_0.c b/monero_crypto/crypto_ops_builder/ref10/ge_p3_0.c new file mode 100644 index 0000000000..401b2935a1 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/ge_p3_dbl.c b/monero_crypto/crypto_ops_builder/ref10/ge_p3_dbl.c new file mode 100644 index 0000000000..0d8a05915d --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/ge_p3_to_cached.c b/monero_crypto/crypto_ops_builder/ref10/ge_p3_to_cached.c new file mode 100644 index 0000000000..bde64228cf --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/ge_p3_to_p2.c b/monero_crypto/crypto_ops_builder/ref10/ge_p3_to_p2.c new file mode 100644 index 0000000000..e532a9e4cb --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/ge_p3_tobytes.c b/monero_crypto/crypto_ops_builder/ref10/ge_p3_tobytes.c new file mode 100644 index 0000000000..21cb2fc656 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/ge_precomp_0.c b/monero_crypto/crypto_ops_builder/ref10/ge_precomp_0.c new file mode 100644 index 0000000000..2e218861d8 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/ge_scalarmult_base.c b/monero_crypto/crypto_ops_builder/ref10/ge_scalarmult_base.c new file mode 100644 index 0000000000..421e4fa0fb --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/ge_sub.c b/monero_crypto/crypto_ops_builder/ref10/ge_sub.c new file mode 100644 index 0000000000..69f3d54062 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/ge_sub.h b/monero_crypto/crypto_ops_builder/ref10/ge_sub.h new file mode 100644 index 0000000000..b4ef1f5dd0 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/ge_sub.q b/monero_crypto/crypto_ops_builder/ref10/ge_sub.q new file mode 100644 index 0000000000..2779a4a201 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/ge_tobytes.c b/monero_crypto/crypto_ops_builder/ref10/ge_tobytes.c new file mode 100644 index 0000000000..31b3d33e09 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/keypair.c b/monero_crypto/crypto_ops_builder/ref10/keypair.c new file mode 100644 index 0000000000..ac6cea2b7a --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/open.c b/monero_crypto/crypto_ops_builder/ref10/open.c new file mode 100644 index 0000000000..1ec4cd2bfd --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/pow22523.h b/monero_crypto/crypto_ops_builder/ref10/pow22523.h new file mode 100644 index 0000000000..60ffe0d34c --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/pow22523.q b/monero_crypto/crypto_ops_builder/ref10/pow22523.q new file mode 100644 index 0000000000..2ce1da9d4d --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/pow225521.h b/monero_crypto/crypto_ops_builder/ref10/pow225521.h new file mode 100644 index 0000000000..109df779a2 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/pow225521.q b/monero_crypto/crypto_ops_builder/ref10/pow225521.q new file mode 100644 index 0000000000..45be57c08a --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/q2h.sh b/monero_crypto/crypto_ops_builder/ref10/q2h.sh new file mode 100644 index 0000000000..47ec5110e8 --- /dev/null +++ b/monero_crypto/crypto_ops_builder/ref10/q2h.sh @@ -0,0 +1,4 @@ +#!/bin/sh +sed 's/^#.*//' \ +| qhasm-generic \ +| sed 's_//\(.*\)$_/*\1 */_' diff --git a/monero_crypto/crypto_ops_builder/ref10/sc.h b/monero_crypto/crypto_ops_builder/ref10/sc.h new file mode 100644 index 0000000000..d32ed2e8ca --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/sc_muladd.c b/monero_crypto/crypto_ops_builder/ref10/sc_muladd.c new file mode 100644 index 0000000000..6f1e9d02d6 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/sc_reduce.c b/monero_crypto/crypto_ops_builder/ref10/sc_reduce.c new file mode 100644 index 0000000000..d01f5a5737 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/sign.c b/monero_crypto/crypto_ops_builder/ref10/sign.c new file mode 100644 index 0000000000..de53742a6c --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10/sqrtm1.h b/monero_crypto/crypto_ops_builder/ref10/sqrtm1.h new file mode 100644 index 0000000000..d8caa23b6a --- /dev/null +++ b/monero_crypto/crypto_ops_builder/ref10/sqrtm1.h @@ -0,0 +1 @@ +-32595792,-7943725,9377950,3500415,12389472,-272473,-25146209,-2005654,326686,11406482 diff --git a/monero_crypto/crypto_ops_builder/ref10/sqrtm1.py b/monero_crypto/crypto_ops_builder/ref10/sqrtm1.py new file mode 100644 index 0000000000..9a47fbc12a --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/MakeCryptoOps.py b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/MakeCryptoOps.py new file mode 100644 index 0000000000..5f8776a493 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/api.h b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/api.h new file mode 100644 index 0000000000..d88dae0c32 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/base.h b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/base.h new file mode 100644 index 0000000000..573bd8a05c --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/base.py b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/base.py new file mode 100644 index 0000000000..84accc8580 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/base2.h b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/base2.h new file mode 100644 index 0000000000..8c538440ff --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/base2.py b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/base2.py new file mode 100644 index 0000000000..5e4e8739d0 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/crypto-ops.h b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/crypto-ops.h new file mode 100644 index 0000000000..b432efade6 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/d.h b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/d.h new file mode 100644 index 0000000000..e25f578350 --- /dev/null +++ b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/d.h @@ -0,0 +1 @@ +-10913610,13857413,-15372611,6949391,114729,-8787816,-6275908,-3247719,-18696448,-12055116 diff --git a/monero_crypto/crypto_ops_builder/ref10CommentedCombined/d.py b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/d.py new file mode 100644 index 0000000000..8995bb86a3 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/d2.h b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/d2.h new file mode 100644 index 0000000000..01aaec7512 --- /dev/null +++ b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/d2.h @@ -0,0 +1 @@ +-21827239,-5839606,-30745221,13898782,229458,15978800,-12551817,-6495438,29715968,9444199 diff --git a/monero_crypto/crypto_ops_builder/ref10CommentedCombined/d2.py b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/d2.py new file mode 100644 index 0000000000..79841758be --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/description b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/description new file mode 100644 index 0000000000..fadc9f9afb --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/designers b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/designers new file mode 100644 index 0000000000..8ee9c735fc --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe.h b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe.h new file mode 100644 index 0000000000..60c308ba46 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_0.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_0.c new file mode 100644 index 0000000000..ec879d7337 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_1.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_1.c new file mode 100644 index 0000000000..8cf7784844 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_add.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_add.c new file mode 100644 index 0000000000..e6a81da202 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_cmov.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_cmov.c new file mode 100644 index 0000000000..8ca584fb19 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_copy.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_copy.c new file mode 100644 index 0000000000..9c5bf865a2 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_frombytes.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_frombytes.c new file mode 100644 index 0000000000..5c17917487 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_invert.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_invert.c new file mode 100644 index 0000000000..bcfdb8ff87 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_isnegative.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_isnegative.c new file mode 100644 index 0000000000..3b2c8b8d52 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_isnonzero.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_isnonzero.c new file mode 100644 index 0000000000..47568001ce --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_mul.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_mul.c new file mode 100644 index 0000000000..26ca8b3682 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_neg.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_neg.c new file mode 100644 index 0000000000..2078ce5284 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_pow22523.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_pow22523.c new file mode 100644 index 0000000000..56675a5902 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_sq.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_sq.c new file mode 100644 index 0000000000..8dd119841c --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_sq2.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_sq2.c new file mode 100644 index 0000000000..026ed3aacf --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_sub.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_sub.c new file mode 100644 index 0000000000..6e26b7df8f --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_tobytes.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/fe_tobytes.c new file mode 100644 index 0000000000..0a63baf9c1 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge.h b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge.h new file mode 100644 index 0000000000..55e95f95b6 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_add.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_add.c new file mode 100644 index 0000000000..da7ff5d2eb --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_add.h b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_add.h new file mode 100644 index 0000000000..7481f8ffbe --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_add.q b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_add.q new file mode 100644 index 0000000000..a6572ab0f8 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_double_scalarmult.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_double_scalarmult.c new file mode 100644 index 0000000000..f8bf4bf775 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_frombytes.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_frombytes.c new file mode 100644 index 0000000000..1a059ee93f --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_madd.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_madd.c new file mode 100644 index 0000000000..622571774b --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_madd.h b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_madd.h new file mode 100644 index 0000000000..ecae84952b --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_madd.q b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_madd.q new file mode 100644 index 0000000000..aa3db454e6 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_msub.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_msub.c new file mode 100644 index 0000000000..741ecbf113 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_msub.h b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_msub.h new file mode 100644 index 0000000000..500f986ba0 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_msub.q b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_msub.q new file mode 100644 index 0000000000..e3cadd882d --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p1p1_to_p2.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p1p1_to_p2.c new file mode 100644 index 0000000000..9bb5013d66 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p1p1_to_p3.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p1p1_to_p3.c new file mode 100644 index 0000000000..2f57b10968 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p2_0.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p2_0.c new file mode 100644 index 0000000000..6191d1e6e4 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p2_dbl.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p2_dbl.c new file mode 100644 index 0000000000..2e332b5cee --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p2_dbl.h b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p2_dbl.h new file mode 100644 index 0000000000..128efed907 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p2_dbl.q b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p2_dbl.q new file mode 100644 index 0000000000..170d42f9a7 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p3_0.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p3_0.c new file mode 100644 index 0000000000..401b2935a1 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p3_dbl.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p3_dbl.c new file mode 100644 index 0000000000..0d8a05915d --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p3_to_cached.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p3_to_cached.c new file mode 100644 index 0000000000..bde64228cf --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p3_to_p2.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p3_to_p2.c new file mode 100644 index 0000000000..e532a9e4cb --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p3_tobytes.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_p3_tobytes.c new file mode 100644 index 0000000000..21cb2fc656 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_precomp_0.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_precomp_0.c new file mode 100644 index 0000000000..2e218861d8 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_scalarmult_base.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_scalarmult_base.c new file mode 100644 index 0000000000..421e4fa0fb --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_sub.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_sub.c new file mode 100644 index 0000000000..69f3d54062 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_sub.h b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_sub.h new file mode 100644 index 0000000000..b4ef1f5dd0 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_sub.q b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_sub.q new file mode 100644 index 0000000000..2779a4a201 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_tobytes.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/ge_tobytes.c new file mode 100644 index 0000000000..31b3d33e09 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/keypair.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/keypair.c new file mode 100644 index 0000000000..ac6cea2b7a --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/open.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/open.c new file mode 100644 index 0000000000..1ec4cd2bfd --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/pow22523.h b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/pow22523.h new file mode 100644 index 0000000000..60ffe0d34c --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/pow22523.q b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/pow22523.q new file mode 100644 index 0000000000..2ce1da9d4d --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/pow225521.h b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/pow225521.h new file mode 100644 index 0000000000..109df779a2 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/pow225521.q b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/pow225521.q new file mode 100644 index 0000000000..45be57c08a --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/q2h.sh b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/q2h.sh new file mode 100644 index 0000000000..47ec5110e8 --- /dev/null +++ b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/q2h.sh @@ -0,0 +1,4 @@ +#!/bin/sh +sed 's/^#.*//' \ +| qhasm-generic \ +| sed 's_//\(.*\)$_/*\1 */_' diff --git a/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sc.h b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sc.h new file mode 100644 index 0000000000..d32ed2e8ca --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sc_muladd.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sc_muladd.c new file mode 100644 index 0000000000..6f1e9d02d6 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sc_reduce.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sc_reduce.c new file mode 100644 index 0000000000..d01f5a5737 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sc_sub.xmr.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sc_sub.xmr.c new file mode 100644 index 0000000000..cd4a50ff00 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/scrap.txt b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/scrap.txt new file mode 100644 index 0000000000..9a02605dbf --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sign.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sign.c new file mode 100644 index 0000000000..de53742a6c --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sqrtm1.h b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sqrtm1.h new file mode 100644 index 0000000000..d8caa23b6a --- /dev/null +++ b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sqrtm1.h @@ -0,0 +1 @@ +-32595792,-7943725,9377950,3500415,12389472,-272473,-25146209,-2005654,326686,11406482 diff --git a/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sqrtm1.py b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/sqrtm1.py new file mode 100644 index 0000000000..9a47fbc12a --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/test.py b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/test.py new file mode 100644 index 0000000000..10fa408ceb --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/ref10CommentedCombined/xmrSpecificOld.c b/monero_crypto/crypto_ops_builder/ref10CommentedCombined/xmrSpecificOld.c new file mode 100644 index 0000000000..e6567c1200 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/sha512-blocks.c b/monero_crypto/crypto_ops_builder/sha512-blocks.c new file mode 100755 index 0000000000..c8dbf0d351 --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/sha512-hash.c b/monero_crypto/crypto_ops_builder/sha512-hash.c new file mode 100755 index 0000000000..f2f292505c --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/sha512.h b/monero_crypto/crypto_ops_builder/sha512.h new file mode 100755 index 0000000000..37376b15de --- /dev/null +++ b/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/monero_crypto/crypto_ops_builder/verify.c b/monero_crypto/crypto_ops_builder/verify.c new file mode 100755 index 0000000000..a04186b607 --- /dev/null +++ b/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/monero_crypto/generic-ops.h b/monero_crypto/generic-ops.h new file mode 100644 index 0000000000..1a135ffcf5 --- /dev/null +++ b/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/monero_crypto/groestl.c b/monero_crypto/groestl.c new file mode 100644 index 0000000000..c8258add33 --- /dev/null +++ b/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/monero_crypto/groestl.h b/monero_crypto/groestl.h new file mode 100644 index 0000000000..89a073a4c3 --- /dev/null +++ b/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/monero_crypto/groestl_tables.h b/monero_crypto/groestl_tables.h new file mode 100644 index 0000000000..8fa6d7a832 --- /dev/null +++ b/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/monero_crypto/hash-extra-blake.c b/monero_crypto/hash-extra-blake.c new file mode 100644 index 0000000000..2364798809 --- /dev/null +++ b/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/monero_crypto/hash-extra-groestl.c b/monero_crypto/hash-extra-groestl.c new file mode 100644 index 0000000000..b150753060 --- /dev/null +++ b/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/monero_crypto/hash-extra-jh.c b/monero_crypto/hash-extra-jh.c new file mode 100644 index 0000000000..8950687d3c --- /dev/null +++ b/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/monero_crypto/hash-extra-skein.c b/monero_crypto/hash-extra-skein.c new file mode 100644 index 0000000000..e63e7da20d --- /dev/null +++ b/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/monero_crypto/hash-ops.h b/monero_crypto/hash-ops.h new file mode 100644 index 0000000000..75593d748f --- /dev/null +++ b/monero_crypto/hash-ops.h @@ -0,0 +1,90 @@ +// Copyright (c) 2017-2018, The Demlabs Inc. Project +// 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/monero_crypto/hash.c b/monero_crypto/hash.c new file mode 100644 index 0000000000..ed95391d88 --- /dev/null +++ b/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/monero_crypto/hash.h b/monero_crypto/hash.h new file mode 100644 index 0000000000..610b4502f1 --- /dev/null +++ b/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/monero_crypto/initializer.h b/monero_crypto/initializer.h new file mode 100644 index 0000000000..eb1d1c069a --- /dev/null +++ b/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/monero_crypto/jh.c b/monero_crypto/jh.c new file mode 100644 index 0000000000..12d5363754 --- /dev/null +++ b/monero_crypto/jh.c @@ -0,0 +1,367 @@ +/*This program gives the 64-bit optimized bitslice implementation of JH using ANSI C + + -------------------------------- + Performance + + Microprocessor: Intel CORE 2 processor (Core 2 Duo Mobile T6600 2.2GHz) + Operating System: 64-bit Ubuntu 10.04 (Linux kernel 2.6.32-22-generic) + Speed for long message: + 1) 45.8 cycles/byte compiler: Intel C++ Compiler 11.1 compilation option: icc -O2 + 2) 56.8 cycles/byte compiler: gcc 4.4.3 compilation option: gcc -O3 + + -------------------------------- + Last Modified: January 16, 2011 +*/ + +#include "jh.h" + +#include <stdint.h> +#include <string.h> + +/*typedef unsigned long long uint64;*/ +typedef uint64_t uint64; + +/*define data alignment for different C compilers*/ +#if defined(__GNUC__) + #define DATA_ALIGN16(x) x __attribute__ ((aligned(16))) +#else + #define DATA_ALIGN16(x) __declspec(align(16)) x +#endif + + +typedef struct { + int hashbitlen; /*the message digest size*/ + unsigned long long databitlen; /*the message size in bits*/ + unsigned long long datasize_in_buffer; /*the size of the message remained in buffer; assumed to be multiple of 8bits except for the last partial block at the end of the message*/ + DATA_ALIGN16(uint64 x[8][2]); /*the 1024-bit state, ( x[i][0] || x[i][1] ) is the ith row of the state in the pseudocode*/ + unsigned char buffer[64]; /*the 512-bit message block to be hashed;*/ +} hashState; + + +/*The initial hash value H(0)*/ +const unsigned char JH224_H0[128]={0x2d,0xfe,0xdd,0x62,0xf9,0x9a,0x98,0xac,0xae,0x7c,0xac,0xd6,0x19,0xd6,0x34,0xe7,0xa4,0x83,0x10,0x5,0xbc,0x30,0x12,0x16,0xb8,0x60,0x38,0xc6,0xc9,0x66,0x14,0x94,0x66,0xd9,0x89,0x9f,0x25,0x80,0x70,0x6f,0xce,0x9e,0xa3,0x1b,0x1d,0x9b,0x1a,0xdc,0x11,0xe8,0x32,0x5f,0x7b,0x36,0x6e,0x10,0xf9,0x94,0x85,0x7f,0x2,0xfa,0x6,0xc1,0x1b,0x4f,0x1b,0x5c,0xd8,0xc8,0x40,0xb3,0x97,0xf6,0xa1,0x7f,0x6e,0x73,0x80,0x99,0xdc,0xdf,0x93,0xa5,0xad,0xea,0xa3,0xd3,0xa4,0x31,0xe8,0xde,0xc9,0x53,0x9a,0x68,0x22,0xb4,0xa9,0x8a,0xec,0x86,0xa1,0xe4,0xd5,0x74,0xac,0x95,0x9c,0xe5,0x6c,0xf0,0x15,0x96,0xd,0xea,0xb5,0xab,0x2b,0xbf,0x96,0x11,0xdc,0xf0,0xdd,0x64,0xea,0x6e}; +const unsigned char JH256_H0[128]={0xeb,0x98,0xa3,0x41,0x2c,0x20,0xd3,0xeb,0x92,0xcd,0xbe,0x7b,0x9c,0xb2,0x45,0xc1,0x1c,0x93,0x51,0x91,0x60,0xd4,0xc7,0xfa,0x26,0x0,0x82,0xd6,0x7e,0x50,0x8a,0x3,0xa4,0x23,0x9e,0x26,0x77,0x26,0xb9,0x45,0xe0,0xfb,0x1a,0x48,0xd4,0x1a,0x94,0x77,0xcd,0xb5,0xab,0x26,0x2,0x6b,0x17,0x7a,0x56,0xf0,0x24,0x42,0xf,0xff,0x2f,0xa8,0x71,0xa3,0x96,0x89,0x7f,0x2e,0x4d,0x75,0x1d,0x14,0x49,0x8,0xf7,0x7d,0xe2,0x62,0x27,0x76,0x95,0xf7,0x76,0x24,0x8f,0x94,0x87,0xd5,0xb6,0x57,0x47,0x80,0x29,0x6c,0x5c,0x5e,0x27,0x2d,0xac,0x8e,0xd,0x6c,0x51,0x84,0x50,0xc6,0x57,0x5,0x7a,0xf,0x7b,0xe4,0xd3,0x67,0x70,0x24,0x12,0xea,0x89,0xe3,0xab,0x13,0xd3,0x1c,0xd7,0x69}; +const unsigned char JH384_H0[128]={0x48,0x1e,0x3b,0xc6,0xd8,0x13,0x39,0x8a,0x6d,0x3b,0x5e,0x89,0x4a,0xde,0x87,0x9b,0x63,0xfa,0xea,0x68,0xd4,0x80,0xad,0x2e,0x33,0x2c,0xcb,0x21,0x48,0xf,0x82,0x67,0x98,0xae,0xc8,0x4d,0x90,0x82,0xb9,0x28,0xd4,0x55,0xea,0x30,0x41,0x11,0x42,0x49,0x36,0xf5,0x55,0xb2,0x92,0x48,0x47,0xec,0xc7,0x25,0xa,0x93,0xba,0xf4,0x3c,0xe1,0x56,0x9b,0x7f,0x8a,0x27,0xdb,0x45,0x4c,0x9e,0xfc,0xbd,0x49,0x63,0x97,0xaf,0xe,0x58,0x9f,0xc2,0x7d,0x26,0xaa,0x80,0xcd,0x80,0xc0,0x8b,0x8c,0x9d,0xeb,0x2e,0xda,0x8a,0x79,0x81,0xe8,0xf8,0xd5,0x37,0x3a,0xf4,0x39,0x67,0xad,0xdd,0xd1,0x7a,0x71,0xa9,0xb4,0xd3,0xbd,0xa4,0x75,0xd3,0x94,0x97,0x6c,0x3f,0xba,0x98,0x42,0x73,0x7f}; +const unsigned char JH512_H0[128]={0x6f,0xd1,0x4b,0x96,0x3e,0x0,0xaa,0x17,0x63,0x6a,0x2e,0x5,0x7a,0x15,0xd5,0x43,0x8a,0x22,0x5e,0x8d,0xc,0x97,0xef,0xb,0xe9,0x34,0x12,0x59,0xf2,0xb3,0xc3,0x61,0x89,0x1d,0xa0,0xc1,0x53,0x6f,0x80,0x1e,0x2a,0xa9,0x5,0x6b,0xea,0x2b,0x6d,0x80,0x58,0x8e,0xcc,0xdb,0x20,0x75,0xba,0xa6,0xa9,0xf,0x3a,0x76,0xba,0xf8,0x3b,0xf7,0x1,0x69,0xe6,0x5,0x41,0xe3,0x4a,0x69,0x46,0xb5,0x8a,0x8e,0x2e,0x6f,0xe6,0x5a,0x10,0x47,0xa7,0xd0,0xc1,0x84,0x3c,0x24,0x3b,0x6e,0x71,0xb1,0x2d,0x5a,0xc1,0x99,0xcf,0x57,0xf6,0xec,0x9d,0xb1,0xf8,0x56,0xa7,0x6,0x88,0x7c,0x57,0x16,0xb1,0x56,0xe3,0xc2,0xfc,0xdf,0xe6,0x85,0x17,0xfb,0x54,0x5a,0x46,0x78,0xcc,0x8c,0xdd,0x4b}; + +/*42 round constants, each round constant is 32-byte (256-bit)*/ +const unsigned char E8_bitslice_roundconstant[42][32]={ +{0x72,0xd5,0xde,0xa2,0xdf,0x15,0xf8,0x67,0x7b,0x84,0x15,0xa,0xb7,0x23,0x15,0x57,0x81,0xab,0xd6,0x90,0x4d,0x5a,0x87,0xf6,0x4e,0x9f,0x4f,0xc5,0xc3,0xd1,0x2b,0x40}, +{0xea,0x98,0x3a,0xe0,0x5c,0x45,0xfa,0x9c,0x3,0xc5,0xd2,0x99,0x66,0xb2,0x99,0x9a,0x66,0x2,0x96,0xb4,0xf2,0xbb,0x53,0x8a,0xb5,0x56,0x14,0x1a,0x88,0xdb,0xa2,0x31}, +{0x3,0xa3,0x5a,0x5c,0x9a,0x19,0xe,0xdb,0x40,0x3f,0xb2,0xa,0x87,0xc1,0x44,0x10,0x1c,0x5,0x19,0x80,0x84,0x9e,0x95,0x1d,0x6f,0x33,0xeb,0xad,0x5e,0xe7,0xcd,0xdc}, +{0x10,0xba,0x13,0x92,0x2,0xbf,0x6b,0x41,0xdc,0x78,0x65,0x15,0xf7,0xbb,0x27,0xd0,0xa,0x2c,0x81,0x39,0x37,0xaa,0x78,0x50,0x3f,0x1a,0xbf,0xd2,0x41,0x0,0x91,0xd3}, +{0x42,0x2d,0x5a,0xd,0xf6,0xcc,0x7e,0x90,0xdd,0x62,0x9f,0x9c,0x92,0xc0,0x97,0xce,0x18,0x5c,0xa7,0xb,0xc7,0x2b,0x44,0xac,0xd1,0xdf,0x65,0xd6,0x63,0xc6,0xfc,0x23}, +{0x97,0x6e,0x6c,0x3,0x9e,0xe0,0xb8,0x1a,0x21,0x5,0x45,0x7e,0x44,0x6c,0xec,0xa8,0xee,0xf1,0x3,0xbb,0x5d,0x8e,0x61,0xfa,0xfd,0x96,0x97,0xb2,0x94,0x83,0x81,0x97}, +{0x4a,0x8e,0x85,0x37,0xdb,0x3,0x30,0x2f,0x2a,0x67,0x8d,0x2d,0xfb,0x9f,0x6a,0x95,0x8a,0xfe,0x73,0x81,0xf8,0xb8,0x69,0x6c,0x8a,0xc7,0x72,0x46,0xc0,0x7f,0x42,0x14}, +{0xc5,0xf4,0x15,0x8f,0xbd,0xc7,0x5e,0xc4,0x75,0x44,0x6f,0xa7,0x8f,0x11,0xbb,0x80,0x52,0xde,0x75,0xb7,0xae,0xe4,0x88,0xbc,0x82,0xb8,0x0,0x1e,0x98,0xa6,0xa3,0xf4}, +{0x8e,0xf4,0x8f,0x33,0xa9,0xa3,0x63,0x15,0xaa,0x5f,0x56,0x24,0xd5,0xb7,0xf9,0x89,0xb6,0xf1,0xed,0x20,0x7c,0x5a,0xe0,0xfd,0x36,0xca,0xe9,0x5a,0x6,0x42,0x2c,0x36}, +{0xce,0x29,0x35,0x43,0x4e,0xfe,0x98,0x3d,0x53,0x3a,0xf9,0x74,0x73,0x9a,0x4b,0xa7,0xd0,0xf5,0x1f,0x59,0x6f,0x4e,0x81,0x86,0xe,0x9d,0xad,0x81,0xaf,0xd8,0x5a,0x9f}, +{0xa7,0x5,0x6,0x67,0xee,0x34,0x62,0x6a,0x8b,0xb,0x28,0xbe,0x6e,0xb9,0x17,0x27,0x47,0x74,0x7,0x26,0xc6,0x80,0x10,0x3f,0xe0,0xa0,0x7e,0x6f,0xc6,0x7e,0x48,0x7b}, +{0xd,0x55,0xa,0xa5,0x4a,0xf8,0xa4,0xc0,0x91,0xe3,0xe7,0x9f,0x97,0x8e,0xf1,0x9e,0x86,0x76,0x72,0x81,0x50,0x60,0x8d,0xd4,0x7e,0x9e,0x5a,0x41,0xf3,0xe5,0xb0,0x62}, +{0xfc,0x9f,0x1f,0xec,0x40,0x54,0x20,0x7a,0xe3,0xe4,0x1a,0x0,0xce,0xf4,0xc9,0x84,0x4f,0xd7,0x94,0xf5,0x9d,0xfa,0x95,0xd8,0x55,0x2e,0x7e,0x11,0x24,0xc3,0x54,0xa5}, +{0x5b,0xdf,0x72,0x28,0xbd,0xfe,0x6e,0x28,0x78,0xf5,0x7f,0xe2,0xf,0xa5,0xc4,0xb2,0x5,0x89,0x7c,0xef,0xee,0x49,0xd3,0x2e,0x44,0x7e,0x93,0x85,0xeb,0x28,0x59,0x7f}, +{0x70,0x5f,0x69,0x37,0xb3,0x24,0x31,0x4a,0x5e,0x86,0x28,0xf1,0x1d,0xd6,0xe4,0x65,0xc7,0x1b,0x77,0x4,0x51,0xb9,0x20,0xe7,0x74,0xfe,0x43,0xe8,0x23,0xd4,0x87,0x8a}, +{0x7d,0x29,0xe8,0xa3,0x92,0x76,0x94,0xf2,0xdd,0xcb,0x7a,0x9,0x9b,0x30,0xd9,0xc1,0x1d,0x1b,0x30,0xfb,0x5b,0xdc,0x1b,0xe0,0xda,0x24,0x49,0x4f,0xf2,0x9c,0x82,0xbf}, +{0xa4,0xe7,0xba,0x31,0xb4,0x70,0xbf,0xff,0xd,0x32,0x44,0x5,0xde,0xf8,0xbc,0x48,0x3b,0xae,0xfc,0x32,0x53,0xbb,0xd3,0x39,0x45,0x9f,0xc3,0xc1,0xe0,0x29,0x8b,0xa0}, +{0xe5,0xc9,0x5,0xfd,0xf7,0xae,0x9,0xf,0x94,0x70,0x34,0x12,0x42,0x90,0xf1,0x34,0xa2,0x71,0xb7,0x1,0xe3,0x44,0xed,0x95,0xe9,0x3b,0x8e,0x36,0x4f,0x2f,0x98,0x4a}, +{0x88,0x40,0x1d,0x63,0xa0,0x6c,0xf6,0x15,0x47,0xc1,0x44,0x4b,0x87,0x52,0xaf,0xff,0x7e,0xbb,0x4a,0xf1,0xe2,0xa,0xc6,0x30,0x46,0x70,0xb6,0xc5,0xcc,0x6e,0x8c,0xe6}, +{0xa4,0xd5,0xa4,0x56,0xbd,0x4f,0xca,0x0,0xda,0x9d,0x84,0x4b,0xc8,0x3e,0x18,0xae,0x73,0x57,0xce,0x45,0x30,0x64,0xd1,0xad,0xe8,0xa6,0xce,0x68,0x14,0x5c,0x25,0x67}, +{0xa3,0xda,0x8c,0xf2,0xcb,0xe,0xe1,0x16,0x33,0xe9,0x6,0x58,0x9a,0x94,0x99,0x9a,0x1f,0x60,0xb2,0x20,0xc2,0x6f,0x84,0x7b,0xd1,0xce,0xac,0x7f,0xa0,0xd1,0x85,0x18}, +{0x32,0x59,0x5b,0xa1,0x8d,0xdd,0x19,0xd3,0x50,0x9a,0x1c,0xc0,0xaa,0xa5,0xb4,0x46,0x9f,0x3d,0x63,0x67,0xe4,0x4,0x6b,0xba,0xf6,0xca,0x19,0xab,0xb,0x56,0xee,0x7e}, +{0x1f,0xb1,0x79,0xea,0xa9,0x28,0x21,0x74,0xe9,0xbd,0xf7,0x35,0x3b,0x36,0x51,0xee,0x1d,0x57,0xac,0x5a,0x75,0x50,0xd3,0x76,0x3a,0x46,0xc2,0xfe,0xa3,0x7d,0x70,0x1}, +{0xf7,0x35,0xc1,0xaf,0x98,0xa4,0xd8,0x42,0x78,0xed,0xec,0x20,0x9e,0x6b,0x67,0x79,0x41,0x83,0x63,0x15,0xea,0x3a,0xdb,0xa8,0xfa,0xc3,0x3b,0x4d,0x32,0x83,0x2c,0x83}, +{0xa7,0x40,0x3b,0x1f,0x1c,0x27,0x47,0xf3,0x59,0x40,0xf0,0x34,0xb7,0x2d,0x76,0x9a,0xe7,0x3e,0x4e,0x6c,0xd2,0x21,0x4f,0xfd,0xb8,0xfd,0x8d,0x39,0xdc,0x57,0x59,0xef}, +{0x8d,0x9b,0xc,0x49,0x2b,0x49,0xeb,0xda,0x5b,0xa2,0xd7,0x49,0x68,0xf3,0x70,0xd,0x7d,0x3b,0xae,0xd0,0x7a,0x8d,0x55,0x84,0xf5,0xa5,0xe9,0xf0,0xe4,0xf8,0x8e,0x65}, +{0xa0,0xb8,0xa2,0xf4,0x36,0x10,0x3b,0x53,0xc,0xa8,0x7,0x9e,0x75,0x3e,0xec,0x5a,0x91,0x68,0x94,0x92,0x56,0xe8,0x88,0x4f,0x5b,0xb0,0x5c,0x55,0xf8,0xba,0xbc,0x4c}, +{0xe3,0xbb,0x3b,0x99,0xf3,0x87,0x94,0x7b,0x75,0xda,0xf4,0xd6,0x72,0x6b,0x1c,0x5d,0x64,0xae,0xac,0x28,0xdc,0x34,0xb3,0x6d,0x6c,0x34,0xa5,0x50,0xb8,0x28,0xdb,0x71}, +{0xf8,0x61,0xe2,0xf2,0x10,0x8d,0x51,0x2a,0xe3,0xdb,0x64,0x33,0x59,0xdd,0x75,0xfc,0x1c,0xac,0xbc,0xf1,0x43,0xce,0x3f,0xa2,0x67,0xbb,0xd1,0x3c,0x2,0xe8,0x43,0xb0}, +{0x33,0xa,0x5b,0xca,0x88,0x29,0xa1,0x75,0x7f,0x34,0x19,0x4d,0xb4,0x16,0x53,0x5c,0x92,0x3b,0x94,0xc3,0xe,0x79,0x4d,0x1e,0x79,0x74,0x75,0xd7,0xb6,0xee,0xaf,0x3f}, +{0xea,0xa8,0xd4,0xf7,0xbe,0x1a,0x39,0x21,0x5c,0xf4,0x7e,0x9,0x4c,0x23,0x27,0x51,0x26,0xa3,0x24,0x53,0xba,0x32,0x3c,0xd2,0x44,0xa3,0x17,0x4a,0x6d,0xa6,0xd5,0xad}, +{0xb5,0x1d,0x3e,0xa6,0xaf,0xf2,0xc9,0x8,0x83,0x59,0x3d,0x98,0x91,0x6b,0x3c,0x56,0x4c,0xf8,0x7c,0xa1,0x72,0x86,0x60,0x4d,0x46,0xe2,0x3e,0xcc,0x8,0x6e,0xc7,0xf6}, +{0x2f,0x98,0x33,0xb3,0xb1,0xbc,0x76,0x5e,0x2b,0xd6,0x66,0xa5,0xef,0xc4,0xe6,0x2a,0x6,0xf4,0xb6,0xe8,0xbe,0xc1,0xd4,0x36,0x74,0xee,0x82,0x15,0xbc,0xef,0x21,0x63}, +{0xfd,0xc1,0x4e,0xd,0xf4,0x53,0xc9,0x69,0xa7,0x7d,0x5a,0xc4,0x6,0x58,0x58,0x26,0x7e,0xc1,0x14,0x16,0x6,0xe0,0xfa,0x16,0x7e,0x90,0xaf,0x3d,0x28,0x63,0x9d,0x3f}, +{0xd2,0xc9,0xf2,0xe3,0x0,0x9b,0xd2,0xc,0x5f,0xaa,0xce,0x30,0xb7,0xd4,0xc,0x30,0x74,0x2a,0x51,0x16,0xf2,0xe0,0x32,0x98,0xd,0xeb,0x30,0xd8,0xe3,0xce,0xf8,0x9a}, +{0x4b,0xc5,0x9e,0x7b,0xb5,0xf1,0x79,0x92,0xff,0x51,0xe6,0x6e,0x4,0x86,0x68,0xd3,0x9b,0x23,0x4d,0x57,0xe6,0x96,0x67,0x31,0xcc,0xe6,0xa6,0xf3,0x17,0xa,0x75,0x5}, +{0xb1,0x76,0x81,0xd9,0x13,0x32,0x6c,0xce,0x3c,0x17,0x52,0x84,0xf8,0x5,0xa2,0x62,0xf4,0x2b,0xcb,0xb3,0x78,0x47,0x15,0x47,0xff,0x46,0x54,0x82,0x23,0x93,0x6a,0x48}, +{0x38,0xdf,0x58,0x7,0x4e,0x5e,0x65,0x65,0xf2,0xfc,0x7c,0x89,0xfc,0x86,0x50,0x8e,0x31,0x70,0x2e,0x44,0xd0,0xb,0xca,0x86,0xf0,0x40,0x9,0xa2,0x30,0x78,0x47,0x4e}, +{0x65,0xa0,0xee,0x39,0xd1,0xf7,0x38,0x83,0xf7,0x5e,0xe9,0x37,0xe4,0x2c,0x3a,0xbd,0x21,0x97,0xb2,0x26,0x1,0x13,0xf8,0x6f,0xa3,0x44,0xed,0xd1,0xef,0x9f,0xde,0xe7}, +{0x8b,0xa0,0xdf,0x15,0x76,0x25,0x92,0xd9,0x3c,0x85,0xf7,0xf6,0x12,0xdc,0x42,0xbe,0xd8,0xa7,0xec,0x7c,0xab,0x27,0xb0,0x7e,0x53,0x8d,0x7d,0xda,0xaa,0x3e,0xa8,0xde}, +{0xaa,0x25,0xce,0x93,0xbd,0x2,0x69,0xd8,0x5a,0xf6,0x43,0xfd,0x1a,0x73,0x8,0xf9,0xc0,0x5f,0xef,0xda,0x17,0x4a,0x19,0xa5,0x97,0x4d,0x66,0x33,0x4c,0xfd,0x21,0x6a}, +{0x35,0xb4,0x98,0x31,0xdb,0x41,0x15,0x70,0xea,0x1e,0xf,0xbb,0xed,0xcd,0x54,0x9b,0x9a,0xd0,0x63,0xa1,0x51,0x97,0x40,0x72,0xf6,0x75,0x9d,0xbf,0x91,0x47,0x6f,0xe2}}; + + +static void E8(hashState *state); /*The bijective function E8, in bitslice form*/ +static void F8(hashState *state); /*The compression function F8 */ + +/*The API functions*/ +static HashReturn Init(hashState *state, int hashbitlen); +static HashReturn Update(hashState *state, const BitSequence *data, DataLength databitlen); +static HashReturn Final(hashState *state, BitSequence *hashval); +HashReturn jh_hash(int hashbitlen, const BitSequence *data,DataLength databitlen, BitSequence *hashval); + +/*swapping bit 2i with bit 2i+1 of 64-bit x*/ +#define SWAP1(x) (x) = ((((x) & 0x5555555555555555ULL) << 1) | (((x) & 0xaaaaaaaaaaaaaaaaULL) >> 1)); +/*swapping bits 4i||4i+1 with bits 4i+2||4i+3 of 64-bit x*/ +#define SWAP2(x) (x) = ((((x) & 0x3333333333333333ULL) << 2) | (((x) & 0xccccccccccccccccULL) >> 2)); +/*swapping bits 8i||8i+1||8i+2||8i+3 with bits 8i+4||8i+5||8i+6||8i+7 of 64-bit x*/ +#define SWAP4(x) (x) = ((((x) & 0x0f0f0f0f0f0f0f0fULL) << 4) | (((x) & 0xf0f0f0f0f0f0f0f0ULL) >> 4)); +/*swapping bits 16i||16i+1||......||16i+7 with bits 16i+8||16i+9||......||16i+15 of 64-bit x*/ +#define SWAP8(x) (x) = ((((x) & 0x00ff00ff00ff00ffULL) << 8) | (((x) & 0xff00ff00ff00ff00ULL) >> 8)); +/*swapping bits 32i||32i+1||......||32i+15 with bits 32i+16||32i+17||......||32i+31 of 64-bit x*/ +#define SWAP16(x) (x) = ((((x) & 0x0000ffff0000ffffULL) << 16) | (((x) & 0xffff0000ffff0000ULL) >> 16)); +/*swapping bits 64i||64i+1||......||64i+31 with bits 64i+32||64i+33||......||64i+63 of 64-bit x*/ +#define SWAP32(x) (x) = (((x) << 32) | ((x) >> 32)); + +/*The MDS transform*/ +#define L(m0,m1,m2,m3,m4,m5,m6,m7) \ + (m4) ^= (m1); \ + (m5) ^= (m2); \ + (m6) ^= (m0) ^ (m3); \ + (m7) ^= (m0); \ + (m0) ^= (m5); \ + (m1) ^= (m6); \ + (m2) ^= (m4) ^ (m7); \ + (m3) ^= (m4); + +/*Two Sboxes are computed in parallel, each Sbox implements S0 and S1, selected by a constant bit*/ +/*The reason to compute two Sboxes in parallel is to try to fully utilize the parallel processing power*/ +#define SS(m0,m1,m2,m3,m4,m5,m6,m7,cc0,cc1) \ + m3 = ~(m3); \ + m7 = ~(m7); \ + m0 ^= ((~(m2)) & (cc0)); \ + m4 ^= ((~(m6)) & (cc1)); \ + temp0 = (cc0) ^ ((m0) & (m1));\ + temp1 = (cc1) ^ ((m4) & (m5));\ + m0 ^= ((m2) & (m3)); \ + m4 ^= ((m6) & (m7)); \ + m3 ^= ((~(m1)) & (m2)); \ + m7 ^= ((~(m5)) & (m6)); \ + m1 ^= ((m0) & (m2)); \ + m5 ^= ((m4) & (m6)); \ + m2 ^= ((m0) & (~(m3))); \ + m6 ^= ((m4) & (~(m7))); \ + m0 ^= ((m1) | (m3)); \ + m4 ^= ((m5) | (m7)); \ + m3 ^= ((m1) & (m2)); \ + m7 ^= ((m5) & (m6)); \ + m1 ^= (temp0 & (m0)); \ + m5 ^= (temp1 & (m4)); \ + m2 ^= temp0; \ + m6 ^= temp1; + +/*The bijective function E8, in bitslice form*/ +static void E8(hashState *state) +{ + uint64 i,roundnumber,temp0,temp1; + + for (roundnumber = 0; roundnumber < 42; roundnumber = roundnumber+7) { + /*round 7*roundnumber+0: Sbox, MDS and Swapping layers*/ + for (i = 0; i < 2; i++) { + SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+0])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+0])[i+2] ); + L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]); + SWAP1(state->x[1][i]); SWAP1(state->x[3][i]); SWAP1(state->x[5][i]); SWAP1(state->x[7][i]); + } + + /*round 7*roundnumber+1: Sbox, MDS and Swapping layers*/ + for (i = 0; i < 2; i++) { + SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+1])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+1])[i+2] ); + L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]); + SWAP2(state->x[1][i]); SWAP2(state->x[3][i]); SWAP2(state->x[5][i]); SWAP2(state->x[7][i]); + } + + /*round 7*roundnumber+2: Sbox, MDS and Swapping layers*/ + for (i = 0; i < 2; i++) { + SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+2])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+2])[i+2] ); + L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]); + SWAP4(state->x[1][i]); SWAP4(state->x[3][i]); SWAP4(state->x[5][i]); SWAP4(state->x[7][i]); + } + + /*round 7*roundnumber+3: Sbox, MDS and Swapping layers*/ + for (i = 0; i < 2; i++) { + SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+3])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+3])[i+2] ); + L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]); + SWAP8(state->x[1][i]); SWAP8(state->x[3][i]); SWAP8(state->x[5][i]); SWAP8(state->x[7][i]); + } + + /*round 7*roundnumber+4: Sbox, MDS and Swapping layers*/ + for (i = 0; i < 2; i++) { + SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+4])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+4])[i+2] ); + L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]); + SWAP16(state->x[1][i]); SWAP16(state->x[3][i]); SWAP16(state->x[5][i]); SWAP16(state->x[7][i]); + } + + /*round 7*roundnumber+5: Sbox, MDS and Swapping layers*/ + for (i = 0; i < 2; i++) { + SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+5])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+5])[i+2] ); + L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]); + SWAP32(state->x[1][i]); SWAP32(state->x[3][i]); SWAP32(state->x[5][i]); SWAP32(state->x[7][i]); + } + + /*round 7*roundnumber+6: Sbox and MDS layers*/ + for (i = 0; i < 2; i++) { + SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+6])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+6])[i+2] ); + L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]); + } + /*round 7*roundnumber+6: swapping layer*/ + for (i = 1; i < 8; i = i+2) { + temp0 = state->x[i][0]; state->x[i][0] = state->x[i][1]; state->x[i][1] = temp0; + } + } + +} + +/*The compression function F8 */ +static void F8(hashState *state) +{ + uint64 i; + + /*xor the 512-bit message with the fist half of the 1024-bit hash state*/ + for (i = 0; i < 8; i++) state->x[i >> 1][i & 1] ^= ((uint64*)state->buffer)[i]; + + /*the bijective function E8 */ + E8(state); + + /*xor the 512-bit message with the second half of the 1024-bit hash state*/ + for (i = 0; i < 8; i++) state->x[(8+i) >> 1][(8+i) & 1] ^= ((uint64*)state->buffer)[i]; +} + +/*before hashing a message, initialize the hash state as H0 */ +static HashReturn Init(hashState *state, int hashbitlen) +{ + state->databitlen = 0; + state->datasize_in_buffer = 0; + + /*initialize the initial hash value of JH*/ + state->hashbitlen = hashbitlen; + + /*load the intital hash value into state*/ + switch (hashbitlen) + { + case 224: memcpy(state->x,JH224_H0,128); break; + case 256: memcpy(state->x,JH256_H0,128); break; + case 384: memcpy(state->x,JH384_H0,128); break; + case 512: memcpy(state->x,JH512_H0,128); break; + } + + return(SUCCESS); +} + + +/*hash each 512-bit message block, except the last partial block*/ +static HashReturn Update(hashState *state, const BitSequence *data, DataLength databitlen) +{ + DataLength index; /*the starting address of the data to be compressed*/ + + state->databitlen += databitlen; + index = 0; + + /*if there is remaining data in the buffer, fill it to a full message block first*/ + /*we assume that the size of the data in the buffer is the multiple of 8 bits if it is not at the end of a message*/ + + /*There is data in the buffer, but the incoming data is insufficient for a full block*/ + if ( (state->datasize_in_buffer > 0 ) && (( state->datasize_in_buffer + databitlen) < 512) ) { + if ( (databitlen & 7) == 0 ) { + memcpy(state->buffer + (state->datasize_in_buffer >> 3), data, 64-(state->datasize_in_buffer >> 3)) ; + } + else memcpy(state->buffer + (state->datasize_in_buffer >> 3), data, 64-(state->datasize_in_buffer >> 3)+1) ; + state->datasize_in_buffer += databitlen; + databitlen = 0; + } + + /*There is data in the buffer, and the incoming data is sufficient for a full block*/ + if ( (state->datasize_in_buffer > 0 ) && (( state->datasize_in_buffer + databitlen) >= 512) ) { + memcpy( state->buffer + (state->datasize_in_buffer >> 3), data, 64-(state->datasize_in_buffer >> 3) ) ; + index = 64-(state->datasize_in_buffer >> 3); + databitlen = databitlen - (512 - state->datasize_in_buffer); + F8(state); + state->datasize_in_buffer = 0; + } + + /*hash the remaining full message blocks*/ + for ( ; databitlen >= 512; index = index+64, databitlen = databitlen - 512) { + memcpy(state->buffer, data+index, 64); + F8(state); + } + + /*store the partial block into buffer, assume that -- if part of the last byte is not part of the message, then that part consists of 0 bits*/ + if ( databitlen > 0) { + if ((databitlen & 7) == 0) + memcpy(state->buffer, data+index, (databitlen & 0x1ff) >> 3); + else + memcpy(state->buffer, data+index, ((databitlen & 0x1ff) >> 3)+1); + state->datasize_in_buffer = databitlen; + } + + return(SUCCESS); +} + +/*pad the message, process the padded block(s), truncate the hash value H to obtain the message digest*/ +static HashReturn Final(hashState *state, BitSequence *hashval) +{ + unsigned int i; + + if ( (state->databitlen & 0x1ff) == 0 ) { + /*pad the message when databitlen is multiple of 512 bits, then process the padded block*/ + memset(state->buffer, 0, 64); + state->buffer[0] = 0x80; + state->buffer[63] = state->databitlen & 0xff; + state->buffer[62] = (state->databitlen >> 8) & 0xff; + state->buffer[61] = (state->databitlen >> 16) & 0xff; + state->buffer[60] = (state->databitlen >> 24) & 0xff; + state->buffer[59] = (state->databitlen >> 32) & 0xff; + state->buffer[58] = (state->databitlen >> 40) & 0xff; + state->buffer[57] = (state->databitlen >> 48) & 0xff; + state->buffer[56] = (state->databitlen >> 56) & 0xff; + F8(state); + } + else { + /*set the rest of the bytes in the buffer to 0*/ + if ( (state->datasize_in_buffer & 7) == 0) + for (i = (state->databitlen & 0x1ff) >> 3; i < 64; i++) state->buffer[i] = 0; + else + for (i = ((state->databitlen & 0x1ff) >> 3)+1; i < 64; i++) state->buffer[i] = 0; + + /*pad and process the partial block when databitlen is not multiple of 512 bits, then hash the padded blocks*/ + state->buffer[((state->databitlen & 0x1ff) >> 3)] |= 1 << (7- (state->databitlen & 7)); + + F8(state); + memset(state->buffer, 0, 64); + state->buffer[63] = state->databitlen & 0xff; + state->buffer[62] = (state->databitlen >> 8) & 0xff; + state->buffer[61] = (state->databitlen >> 16) & 0xff; + state->buffer[60] = (state->databitlen >> 24) & 0xff; + state->buffer[59] = (state->databitlen >> 32) & 0xff; + state->buffer[58] = (state->databitlen >> 40) & 0xff; + state->buffer[57] = (state->databitlen >> 48) & 0xff; + state->buffer[56] = (state->databitlen >> 56) & 0xff; + F8(state); + } + + /*truncating the final hash value to generate the message digest*/ + switch(state->hashbitlen) { + case 224: memcpy(hashval,(unsigned char*)state->x+64+36,28); break; + case 256: memcpy(hashval,(unsigned char*)state->x+64+32,32); break; + case 384: memcpy(hashval,(unsigned char*)state->x+64+16,48); break; + case 512: memcpy(hashval,(unsigned char*)state->x+64,64); break; + } + + return(SUCCESS); +} + +/* hash a message, + three inputs: message digest size in bits (hashbitlen); message (data); message length in bits (databitlen) + one output: message digest (hashval) +*/ +HashReturn jh_hash(int hashbitlen, const BitSequence *data,DataLength databitlen, BitSequence *hashval) +{ + hashState state; + + if ( hashbitlen == 224 || hashbitlen == 256 || hashbitlen == 384 || hashbitlen == 512 ) { + Init(&state, hashbitlen); + Update(&state, data, databitlen); + Final(&state, hashval); + return SUCCESS; + } + else + return(BAD_HASHLEN); +} diff --git a/monero_crypto/jh.h b/monero_crypto/jh.h new file mode 100644 index 0000000000..627a9ff058 --- /dev/null +++ b/monero_crypto/jh.h @@ -0,0 +1,21 @@ +/*This program gives the 64-bit optimized bitslice implementation of JH using ANSI C + + -------------------------------- + Performance + + Microprocessor: Intel CORE 2 processor (Core 2 Duo Mobile T6600 2.2GHz) + Operating System: 64-bit Ubuntu 10.04 (Linux kernel 2.6.32-22-generic) + Speed for long message: + 1) 45.8 cycles/byte compiler: Intel C++ Compiler 11.1 compilation option: icc -O2 + 2) 56.8 cycles/byte compiler: gcc 4.4.3 compilation option: gcc -O3 + + -------------------------------- + Last Modified: January 16, 2011 +*/ +#pragma once + +typedef unsigned char BitSequence; +typedef unsigned long long DataLength; +typedef enum {SUCCESS = 0, FAIL = 1, BAD_HASHLEN = 2} HashReturn; + +HashReturn jh_hash(int hashbitlen, const BitSequence *data, DataLength databitlen, BitSequence *hashval); diff --git a/monero_crypto/keccak.c b/monero_crypto/keccak.c new file mode 100644 index 0000000000..fc6d487c2f --- /dev/null +++ b/monero_crypto/keccak.c @@ -0,0 +1,124 @@ +// keccak.c +// 19-Nov-11 Markku-Juhani O. Saarinen <mjos@iki.fi> +// A baseline Keccak (3rd round) implementation. + +#include <stdio.h> +#include <stdlib.h> +#include "hash-ops.h" +#include "keccak.h" + +const uint64_t keccakf_rndc[24] = +{ + 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, + 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, + 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, + 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, + 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, + 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, + 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, + 0x8000000000008080, 0x0000000080000001, 0x8000000080008008 +}; + +const int keccakf_rotc[24] = +{ + 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, + 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44 +}; + +const int keccakf_piln[24] = +{ + 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, + 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1 +}; + +// update the state with given number of rounds + +void keccakf(uint64_t st[25], int rounds) +{ + int i, j, round; + uint64_t t, bc[5]; + + for (round = 0; round < rounds; round++) { + + // Theta + for (i = 0; i < 5; i++) + bc[i] = st[i] ^ st[i + 5] ^ st[i + 10] ^ st[i + 15] ^ st[i + 20]; + + for (i = 0; i < 5; i++) { + t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1); + for (j = 0; j < 25; j += 5) + st[j + i] ^= t; + } + + // Rho Pi + t = st[1]; + for (i = 0; i < 24; i++) { + j = keccakf_piln[i]; + bc[0] = st[j]; + st[j] = ROTL64(t, keccakf_rotc[i]); + t = bc[0]; + } + + // Chi + for (j = 0; j < 25; j += 5) { + for (i = 0; i < 5; i++) + bc[i] = st[j + i]; + for (i = 0; i < 5; i++) + st[j + i] ^= (~bc[(i + 1) % 5]) & bc[(i + 2) % 5]; + } + + // Iota + st[0] ^= keccakf_rndc[round]; + } +} + +// compute a keccak hash (md) of given byte length from "in" +typedef uint64_t state_t[25]; + +void keccak(const uint8_t *in, size_t inlen, uint8_t *md, int mdlen) +{ + state_t st; + uint8_t temp[144]; + size_t i, rsiz, rsizw; + + if (mdlen <= 0 || mdlen > 200 || sizeof(st) != 200) + { + fprintf(stderr, "Bad keccak use"); + abort(); + } + + rsiz = sizeof(state_t) == mdlen ? HASH_DATA_AREA : 200 - 2 * mdlen; + rsizw = rsiz / 8; + + memset(st, 0, sizeof(st)); + + for ( ; inlen >= rsiz; inlen -= rsiz, in += rsiz) { + for (i = 0; i < rsizw; i++) + st[i] ^= ((uint64_t *) in)[i]; + keccakf(st, KECCAK_ROUNDS); + } + + // last block and padding + if (inlen >= sizeof(temp) || inlen > rsiz || rsiz - inlen + inlen + 1 >= sizeof(temp) || rsiz == 0 || rsiz - 1 >= sizeof(temp) || rsizw * 8 > sizeof(temp)) + { + fprintf(stderr, "Bad keccak use"); + abort(); + } + + memcpy(temp, in, inlen); + temp[inlen++] = 1; + memset(temp + inlen, 0, rsiz - inlen); + temp[rsiz - 1] |= 0x80; + + for (i = 0; i < rsizw; i++) + st[i] ^= ((uint64_t *) temp)[i]; + + keccakf(st, KECCAK_ROUNDS); + + memcpy(md, st, mdlen); +} + +void keccak1600(const uint8_t *in, size_t inlen, uint8_t *md) +{ + keccak(in, inlen, md, sizeof(state_t)); +} diff --git a/monero_crypto/keccak.h b/monero_crypto/keccak.h new file mode 100644 index 0000000000..fb9d8bd043 --- /dev/null +++ b/monero_crypto/keccak.h @@ -0,0 +1,26 @@ +// keccak.h +// 19-Nov-11 Markku-Juhani O. Saarinen <mjos@iki.fi> + +#ifndef KECCAK_H +#define KECCAK_H + +#include <stdint.h> +#include <string.h> + +#ifndef KECCAK_ROUNDS +#define KECCAK_ROUNDS 24 +#endif + +#ifndef ROTL64 +#define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y)))) +#endif + +// compute a keccak hash (md) of given byte length from "in" +void keccak(const uint8_t *in, size_t inlen, uint8_t *md, int mdlen); + +// update the state +void keccakf(uint64_t st[25], int norounds); + +void keccak1600(const uint8_t *in, size_t inlen, uint8_t *md); + +#endif diff --git a/monero_crypto/oaes_config.h b/monero_crypto/oaes_config.h new file mode 100644 index 0000000000..3fc0e1be5c --- /dev/null +++ b/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/monero_crypto/oaes_lib.c b/monero_crypto/oaes_lib.c new file mode 100644 index 0000000000..0afec62122 --- /dev/null +++ b/monero_crypto/oaes_lib.c @@ -0,0 +1,1500 @@ +/* + * --------------------------------------------------------------------------- + * 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. + * --------------------------------------------------------------------------- + */ +#include <stddef.h> +#include <time.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> + +// OS X, FreeBSD, and OpenBSD don't need malloc.h +#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) \ + && !defined(__DragonFly__) + #include <malloc.h> +#endif + +// ANDROID, FreeBSD, and OpenBSD also don't need timeb.h +#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__ANDROID__) + #include <sys/timeb.h> +#else + #include <sys/time.h> +#endif + +#ifdef WIN32 +#include <process.h> +#else +#include <sys/types.h> +#include <unistd.h> +#endif + +#include "oaes_config.h" +#include "oaes_lib.h" + +#ifdef OAES_HAVE_ISAAC +#include "rand.h" +#endif // OAES_HAVE_ISAAC + +#define OAES_RKEY_LEN 4 +#define OAES_COL_LEN 4 +#define OAES_ROUND_BASE 7 + +// the block is padded +#define OAES_FLAG_PAD 0x01 + +#ifndef min +# define min(a,b) (((a)<(b)) ? (a) : (b)) +#endif /* min */ + +// "OAES<8-bit header version><8-bit type><16-bit options><8-bit flags><56-bit reserved>" +static uint8_t oaes_header[OAES_BLOCK_SIZE] = { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, + /*0*/ 0x4f, 0x41, 0x45, 0x53, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; +static uint8_t oaes_gf_8[] = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 }; + +static uint8_t oaes_sub_byte_value[16][16] = { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, + /*0*/ { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76 }, + /*1*/ { 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0 }, + /*2*/ { 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15 }, + /*3*/ { 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75 }, + /*4*/ { 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84 }, + /*5*/ { 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf }, + /*6*/ { 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8 }, + /*7*/ { 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2 }, + /*8*/ { 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73 }, + /*9*/ { 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb }, + /*a*/ { 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79 }, + /*b*/ { 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08 }, + /*c*/ { 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a }, + /*d*/ { 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e }, + /*e*/ { 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf }, + /*f*/ { 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 }, +}; + +static uint8_t oaes_inv_sub_byte_value[16][16] = { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, + /*0*/ { 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb }, + /*1*/ { 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb }, + /*2*/ { 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e }, + /*3*/ { 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25 }, + /*4*/ { 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92 }, + /*5*/ { 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84 }, + /*6*/ { 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06 }, + /*7*/ { 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b }, + /*8*/ { 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73 }, + /*9*/ { 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e }, + /*a*/ { 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b }, + /*b*/ { 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4 }, + /*c*/ { 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f }, + /*d*/ { 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef }, + /*e*/ { 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61 }, + /*f*/ { 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d }, +}; + +static uint8_t oaes_gf_mul_2[16][16] = { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, + /*0*/ { 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e }, + /*1*/ { 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e }, + /*2*/ { 0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e }, + /*3*/ { 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e }, + /*4*/ { 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e }, + /*5*/ { 0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe }, + /*6*/ { 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde }, + /*7*/ { 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe }, + /*8*/ { 0x1b, 0x19, 0x1f, 0x1d, 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05 }, + /*9*/ { 0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d, 0x23, 0x21, 0x27, 0x25 }, + /*a*/ { 0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55, 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45 }, + /*b*/ { 0x7b, 0x79, 0x7f, 0x7d, 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65 }, + /*c*/ { 0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, 0x83, 0x81, 0x87, 0x85 }, + /*d*/ { 0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5 }, + /*e*/ { 0xdb, 0xd9, 0xdf, 0xdd, 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5 }, + /*f*/ { 0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5 }, +}; + +static uint8_t oaes_gf_mul_3[16][16] = { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, + /*0*/ { 0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11 }, + /*1*/ { 0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21 }, + /*2*/ { 0x60, 0x63, 0x66, 0x65, 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71 }, + /*3*/ { 0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48, 0x4b, 0x4e, 0x4d, 0x44, 0x47, 0x42, 0x41 }, + /*4*/ { 0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9, 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1 }, + /*5*/ { 0xf0, 0xf3, 0xf6, 0xf5, 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1 }, + /*6*/ { 0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd, 0xb4, 0xb7, 0xb2, 0xb1 }, + /*7*/ { 0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99, 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81 }, + /*8*/ { 0x9b, 0x98, 0x9d, 0x9e, 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a }, + /*9*/ { 0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2, 0xb3, 0xb0, 0xb5, 0xb6, 0xbf, 0xbc, 0xb9, 0xba }, + /*a*/ { 0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2, 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea }, + /*b*/ { 0xcb, 0xc8, 0xcd, 0xce, 0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda }, + /*c*/ { 0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, 0x4f, 0x4c, 0x49, 0x4a }, + /*d*/ { 0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62, 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a }, + /*e*/ { 0x3b, 0x38, 0x3d, 0x3e, 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a }, + /*f*/ { 0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a }, +}; + +static uint8_t oaes_gf_mul_9[16][16] = { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, + /*0*/ { 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77 }, + /*1*/ { 0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7 }, + /*2*/ { 0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c }, + /*3*/ { 0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d, 0x94, 0xe3, 0xea, 0xf1, 0xf8, 0xc7, 0xce, 0xd5, 0xdc }, + /*4*/ { 0x76, 0x7f, 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49, 0x3e, 0x37, 0x2c, 0x25, 0x1a, 0x13, 0x08, 0x01 }, + /*5*/ { 0xe6, 0xef, 0xf4, 0xfd, 0xc2, 0xcb, 0xd0, 0xd9, 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98, 0x91 }, + /*6*/ { 0x4d, 0x44, 0x5f, 0x56, 0x69, 0x60, 0x7b, 0x72, 0x05, 0x0c, 0x17, 0x1e, 0x21, 0x28, 0x33, 0x3a }, + /*7*/ { 0xdd, 0xd4, 0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2, 0x95, 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa }, + /*8*/ { 0xec, 0xe5, 0xfe, 0xf7, 0xc8, 0xc1, 0xda, 0xd3, 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92, 0x9b }, + /*9*/ { 0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43, 0x34, 0x3d, 0x26, 0x2f, 0x10, 0x19, 0x02, 0x0b }, + /*a*/ { 0xd7, 0xde, 0xc5, 0xcc, 0xf3, 0xfa, 0xe1, 0xe8, 0x9f, 0x96, 0x8d, 0x84, 0xbb, 0xb2, 0xa9, 0xa0 }, + /*b*/ { 0x47, 0x4e, 0x55, 0x5c, 0x63, 0x6a, 0x71, 0x78, 0x0f, 0x06, 0x1d, 0x14, 0x2b, 0x22, 0x39, 0x30 }, + /*c*/ { 0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5, 0xd2, 0xdb, 0xc0, 0xc9, 0xf6, 0xff, 0xe4, 0xed }, + /*d*/ { 0x0a, 0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35, 0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d }, + /*e*/ { 0xa1, 0xa8, 0xb3, 0xba, 0x85, 0x8c, 0x97, 0x9e, 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6 }, + /*f*/ { 0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46 }, +}; + +static uint8_t oaes_gf_mul_b[16][16] = { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, + /*0*/ { 0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69 }, + /*1*/ { 0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9 }, + /*2*/ { 0x7b, 0x70, 0x6d, 0x66, 0x57, 0x5c, 0x41, 0x4a, 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12 }, + /*3*/ { 0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1, 0xfa, 0x93, 0x98, 0x85, 0x8e, 0xbf, 0xb4, 0xa9, 0xa2 }, + /*4*/ { 0xf6, 0xfd, 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7, 0xae, 0xa5, 0xb8, 0xb3, 0x82, 0x89, 0x94, 0x9f }, + /*5*/ { 0x46, 0x4d, 0x50, 0x5b, 0x6a, 0x61, 0x7c, 0x77, 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2f }, + /*6*/ { 0x8d, 0x86, 0x9b, 0x90, 0xa1, 0xaa, 0xb7, 0xbc, 0xd5, 0xde, 0xc3, 0xc8, 0xf9, 0xf2, 0xef, 0xe4 }, + /*7*/ { 0x3d, 0x36, 0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c, 0x65, 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54 }, + /*8*/ { 0xf7, 0xfc, 0xe1, 0xea, 0xdb, 0xd0, 0xcd, 0xc6, 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95, 0x9e }, + /*9*/ { 0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76, 0x1f, 0x14, 0x09, 0x02, 0x33, 0x38, 0x25, 0x2e }, + /*a*/ { 0x8c, 0x87, 0x9a, 0x91, 0xa0, 0xab, 0xb6, 0xbd, 0xd4, 0xdf, 0xc2, 0xc9, 0xf8, 0xf3, 0xee, 0xe5 }, + /*b*/ { 0x3c, 0x37, 0x2a, 0x21, 0x10, 0x1b, 0x06, 0x0d, 0x64, 0x6f, 0x72, 0x79, 0x48, 0x43, 0x5e, 0x55 }, + /*c*/ { 0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30, 0x59, 0x52, 0x4f, 0x44, 0x75, 0x7e, 0x63, 0x68 }, + /*d*/ { 0xb1, 0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80, 0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8 }, + /*e*/ { 0x7a, 0x71, 0x6c, 0x67, 0x56, 0x5d, 0x40, 0x4b, 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13 }, + /*f*/ { 0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3 }, +}; + +static uint8_t oaes_gf_mul_d[16][16] = { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, + /*0*/ { 0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b }, + /*1*/ { 0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b }, + /*2*/ { 0xbb, 0xb6, 0xa1, 0xac, 0x8f, 0x82, 0x95, 0x98, 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0 }, + /*3*/ { 0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45, 0x48, 0x03, 0x0e, 0x19, 0x14, 0x37, 0x3a, 0x2d, 0x20 }, + /*4*/ { 0x6d, 0x60, 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e, 0x05, 0x08, 0x1f, 0x12, 0x31, 0x3c, 0x2b, 0x26 }, + /*5*/ { 0xbd, 0xb0, 0xa7, 0xaa, 0x89, 0x84, 0x93, 0x9e, 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb, 0xf6 }, + /*6*/ { 0xd6, 0xdb, 0xcc, 0xc1, 0xe2, 0xef, 0xf8, 0xf5, 0xbe, 0xb3, 0xa4, 0xa9, 0x8a, 0x87, 0x90, 0x9d }, + /*7*/ { 0x06, 0x0b, 0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25, 0x6e, 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d }, + /*8*/ { 0xda, 0xd7, 0xc0, 0xcd, 0xee, 0xe3, 0xf4, 0xf9, 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c, 0x91 }, + /*9*/ { 0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29, 0x62, 0x6f, 0x78, 0x75, 0x56, 0x5b, 0x4c, 0x41 }, + /*a*/ { 0x61, 0x6c, 0x7b, 0x76, 0x55, 0x58, 0x4f, 0x42, 0x09, 0x04, 0x13, 0x1e, 0x3d, 0x30, 0x27, 0x2a }, + /*b*/ { 0xb1, 0xbc, 0xab, 0xa6, 0x85, 0x88, 0x9f, 0x92, 0xd9, 0xd4, 0xc3, 0xce, 0xed, 0xe0, 0xf7, 0xfa }, + /*c*/ { 0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94, 0xdf, 0xd2, 0xc5, 0xc8, 0xeb, 0xe6, 0xf1, 0xfc }, + /*d*/ { 0x67, 0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44, 0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c }, + /*e*/ { 0x0c, 0x01, 0x16, 0x1b, 0x38, 0x35, 0x22, 0x2f, 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47 }, + /*f*/ { 0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97 }, +}; + +static uint8_t oaes_gf_mul_e[16][16] = { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, + /*0*/ { 0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a }, + /*1*/ { 0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba }, + /*2*/ { 0xdb, 0xd5, 0xc7, 0xc9, 0xe3, 0xed, 0xff, 0xf1, 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81 }, + /*3*/ { 0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f, 0x11, 0x4b, 0x45, 0x57, 0x59, 0x73, 0x7d, 0x6f, 0x61 }, + /*4*/ { 0xad, 0xa3, 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87, 0xdd, 0xd3, 0xc1, 0xcf, 0xe5, 0xeb, 0xf9, 0xf7 }, + /*5*/ { 0x4d, 0x43, 0x51, 0x5f, 0x75, 0x7b, 0x69, 0x67, 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19, 0x17 }, + /*6*/ { 0x76, 0x78, 0x6a, 0x64, 0x4e, 0x40, 0x52, 0x5c, 0x06, 0x08, 0x1a, 0x14, 0x3e, 0x30, 0x22, 0x2c }, + /*7*/ { 0x96, 0x98, 0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc, 0xe6, 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc }, + /*8*/ { 0x41, 0x4f, 0x5d, 0x53, 0x79, 0x77, 0x65, 0x6b, 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b }, + /*9*/ { 0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b, 0xd1, 0xdf, 0xcd, 0xc3, 0xe9, 0xe7, 0xf5, 0xfb }, + /*a*/ { 0x9a, 0x94, 0x86, 0x88, 0xa2, 0xac, 0xbe, 0xb0, 0xea, 0xe4, 0xf6, 0xf8, 0xd2, 0xdc, 0xce, 0xc0 }, + /*b*/ { 0x7a, 0x74, 0x66, 0x68, 0x42, 0x4c, 0x5e, 0x50, 0x0a, 0x04, 0x16, 0x18, 0x32, 0x3c, 0x2e, 0x20 }, + /*c*/ { 0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6, 0x9c, 0x92, 0x80, 0x8e, 0xa4, 0xaa, 0xb8, 0xb6 }, + /*d*/ { 0x0c, 0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26, 0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56 }, + /*e*/ { 0x37, 0x39, 0x2b, 0x25, 0x0f, 0x01, 0x13, 0x1d, 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d }, + /*f*/ { 0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d }, +}; + +static OAES_RET oaes_sub_byte( uint8_t * byte ) +{ + size_t _x, _y; + + if( NULL == byte ) + return OAES_RET_ARG1; + + _x = _y = *byte; + _x &= 0x0f; + _y &= 0xf0; + _y >>= 4; + *byte = oaes_sub_byte_value[_y][_x]; + + return OAES_RET_SUCCESS; +} + +static OAES_RET oaes_inv_sub_byte( uint8_t * byte ) +{ + size_t _x, _y; + + if( NULL == byte ) + return OAES_RET_ARG1; + + _x = _y = *byte; + _x &= 0x0f; + _y &= 0xf0; + _y >>= 4; + *byte = oaes_inv_sub_byte_value[_y][_x]; + + return OAES_RET_SUCCESS; +} +/* +static OAES_RET oaes_word_rot_right( uint8_t word[OAES_COL_LEN] ) +{ + uint8_t _temp[OAES_COL_LEN]; + + if( NULL == word ) + return OAES_RET_ARG1; + + memcpy( _temp + 1, word, OAES_COL_LEN - 1 ); + _temp[0] = word[OAES_COL_LEN - 1]; + memcpy( word, _temp, OAES_COL_LEN ); + + return OAES_RET_SUCCESS; +} +*/ +static OAES_RET oaes_word_rot_left( uint8_t word[OAES_COL_LEN] ) +{ + uint8_t _temp[OAES_COL_LEN]; + + if( NULL == word ) + return OAES_RET_ARG1; + + memcpy( _temp, word + 1, OAES_COL_LEN - 1 ); + _temp[OAES_COL_LEN - 1] = word[0]; + memcpy( word, _temp, OAES_COL_LEN ); + + return OAES_RET_SUCCESS; +} + +static OAES_RET oaes_shift_rows( uint8_t block[OAES_BLOCK_SIZE] ) +{ + uint8_t _temp[OAES_BLOCK_SIZE]; + + if( NULL == block ) + return OAES_RET_ARG1; + + _temp[0x00] = block[0x00]; + _temp[0x01] = block[0x05]; + _temp[0x02] = block[0x0a]; + _temp[0x03] = block[0x0f]; + _temp[0x04] = block[0x04]; + _temp[0x05] = block[0x09]; + _temp[0x06] = block[0x0e]; + _temp[0x07] = block[0x03]; + _temp[0x08] = block[0x08]; + _temp[0x09] = block[0x0d]; + _temp[0x0a] = block[0x02]; + _temp[0x0b] = block[0x07]; + _temp[0x0c] = block[0x0c]; + _temp[0x0d] = block[0x01]; + _temp[0x0e] = block[0x06]; + _temp[0x0f] = block[0x0b]; + memcpy( block, _temp, OAES_BLOCK_SIZE ); + + return OAES_RET_SUCCESS; +} + +static OAES_RET oaes_inv_shift_rows( uint8_t block[OAES_BLOCK_SIZE] ) +{ + uint8_t _temp[OAES_BLOCK_SIZE]; + + if( NULL == block ) + return OAES_RET_ARG1; + + _temp[0x00] = block[0x00]; + _temp[0x01] = block[0x0d]; + _temp[0x02] = block[0x0a]; + _temp[0x03] = block[0x07]; + _temp[0x04] = block[0x04]; + _temp[0x05] = block[0x01]; + _temp[0x06] = block[0x0e]; + _temp[0x07] = block[0x0b]; + _temp[0x08] = block[0x08]; + _temp[0x09] = block[0x05]; + _temp[0x0a] = block[0x02]; + _temp[0x0b] = block[0x0f]; + _temp[0x0c] = block[0x0c]; + _temp[0x0d] = block[0x09]; + _temp[0x0e] = block[0x06]; + _temp[0x0f] = block[0x03]; + memcpy( block, _temp, OAES_BLOCK_SIZE ); + + return OAES_RET_SUCCESS; +} + +static uint8_t oaes_gf_mul(uint8_t left, uint8_t right) +{ + size_t _x, _y; + + _x = _y = left; + _x &= 0x0f; + _y &= 0xf0; + _y >>= 4; + + switch( right ) + { + case 0x02: + return oaes_gf_mul_2[_y][_x]; + break; + case 0x03: + return oaes_gf_mul_3[_y][_x]; + break; + case 0x09: + return oaes_gf_mul_9[_y][_x]; + break; + case 0x0b: + return oaes_gf_mul_b[_y][_x]; + break; + case 0x0d: + return oaes_gf_mul_d[_y][_x]; + break; + case 0x0e: + return oaes_gf_mul_e[_y][_x]; + break; + default: + return left; + break; + } +} + +static OAES_RET oaes_mix_cols( uint8_t word[OAES_COL_LEN] ) +{ + uint8_t _temp[OAES_COL_LEN]; + + if( NULL == word ) + return OAES_RET_ARG1; + + _temp[0] = oaes_gf_mul(word[0], 0x02) ^ oaes_gf_mul( word[1], 0x03 ) ^ + word[2] ^ word[3]; + _temp[1] = word[0] ^ oaes_gf_mul( word[1], 0x02 ) ^ + oaes_gf_mul( word[2], 0x03 ) ^ word[3]; + _temp[2] = word[0] ^ word[1] ^ + oaes_gf_mul( word[2], 0x02 ) ^ oaes_gf_mul( word[3], 0x03 ); + _temp[3] = oaes_gf_mul( word[0], 0x03 ) ^ word[1] ^ + word[2] ^ oaes_gf_mul( word[3], 0x02 ); + memcpy( word, _temp, OAES_COL_LEN ); + + return OAES_RET_SUCCESS; +} + +static OAES_RET oaes_inv_mix_cols( uint8_t word[OAES_COL_LEN] ) +{ + uint8_t _temp[OAES_COL_LEN]; + + if( NULL == word ) + return OAES_RET_ARG1; + + _temp[0] = oaes_gf_mul( word[0], 0x0e ) ^ oaes_gf_mul( word[1], 0x0b ) ^ + oaes_gf_mul( word[2], 0x0d ) ^ oaes_gf_mul( word[3], 0x09 ); + _temp[1] = oaes_gf_mul( word[0], 0x09 ) ^ oaes_gf_mul( word[1], 0x0e ) ^ + oaes_gf_mul( word[2], 0x0b ) ^ oaes_gf_mul( word[3], 0x0d ); + _temp[2] = oaes_gf_mul( word[0], 0x0d ) ^ oaes_gf_mul( word[1], 0x09 ) ^ + oaes_gf_mul( word[2], 0x0e ) ^ oaes_gf_mul( word[3], 0x0b ); + _temp[3] = oaes_gf_mul( word[0], 0x0b ) ^ oaes_gf_mul( word[1], 0x0d ) ^ + oaes_gf_mul( word[2], 0x09 ) ^ oaes_gf_mul( word[3], 0x0e ); + memcpy( word, _temp, OAES_COL_LEN ); + + return OAES_RET_SUCCESS; +} + +OAES_RET oaes_sprintf( + char * buf, size_t * buf_len, const uint8_t * data, size_t data_len ) +{ + size_t _i, _buf_len_in; + char _temp[4]; + + if( NULL == buf_len ) + return OAES_RET_ARG2; + + _buf_len_in = *buf_len; + *buf_len = data_len * 3 + data_len / OAES_BLOCK_SIZE + 1; + + if( NULL == buf ) + return OAES_RET_SUCCESS; + + if( *buf_len > _buf_len_in ) + return OAES_RET_BUF; + + if( NULL == data ) + return OAES_RET_ARG3; + + strcpy( buf, "" ); + + for( _i = 0; _i < data_len; _i++ ) + { + sprintf( _temp, "%02x ", data[_i] ); + strcat( buf, _temp ); + if( _i && 0 == ( _i + 1 ) % OAES_BLOCK_SIZE ) + strcat( buf, "\n" ); + } + + return OAES_RET_SUCCESS; +} + +#ifdef OAES_HAVE_ISAAC +static void oaes_get_seed( char buf[RANDSIZ + 1] ) +{ + #if !defined(__FreeBSD__) && !defined(__OpenBSD__) + struct timeb timer; + struct tm *gmTimer; + char * _test = NULL; + + ftime (&timer); + gmTimer = gmtime( &timer.time ); + _test = (char *) calloc( sizeof( char ), timer.millitm ); + sprintf( buf, "%04d%02d%02d%02d%02d%02d%03d%p%d", + gmTimer->tm_year + 1900, gmTimer->tm_mon + 1, gmTimer->tm_mday, + gmTimer->tm_hour, gmTimer->tm_min, gmTimer->tm_sec, timer.millitm, + _test + timer.millitm, getpid() ); + #else + struct timeval timer; + struct tm *gmTimer; + char * _test = NULL; + + gettimeofday(&timer, NULL); + gmTimer = gmtime( &timer.tv_sec ); + _test = (char *) calloc( sizeof( char ), timer.tv_usec/1000 ); + sprintf( buf, "%04d%02d%02d%02d%02d%02d%03d%p%d", + gmTimer->tm_year + 1900, gmTimer->tm_mon + 1, gmTimer->tm_mday, + gmTimer->tm_hour, gmTimer->tm_min, gmTimer->tm_sec, timer.tv_usec/1000, + _test + timer.tv_usec/1000, getpid() ); + #endif + + if( _test ) + free( _test ); +} +#else +static uint32_t oaes_get_seed(void) +{ + #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__ANDROID__) + struct timeb timer; + struct tm *gmTimer; + char * _test = NULL; + uint32_t _ret = 0; + + ftime (&timer); + gmTimer = gmtime( &timer.time ); + _test = (char *) calloc( sizeof( char ), timer.millitm ); + _ret = gmTimer->tm_year + 1900 + gmTimer->tm_mon + 1 + gmTimer->tm_mday + + gmTimer->tm_hour + gmTimer->tm_min + gmTimer->tm_sec + timer.millitm + + (uintptr_t) ( _test + timer.millitm ) + getpid(); + #else + struct timeval timer; + struct tm *gmTimer; + char * _test = NULL; + uint32_t _ret = 0; + + gettimeofday(&timer, NULL); + gmTimer = gmtime( &timer.tv_sec ); + _test = (char *) calloc( sizeof( char ), timer.tv_usec/1000 ); + _ret = gmTimer->tm_year + 1900 + gmTimer->tm_mon + 1 + gmTimer->tm_mday + + gmTimer->tm_hour + gmTimer->tm_min + gmTimer->tm_sec + timer.tv_usec/1000 + + (uintptr_t) ( _test + timer.tv_usec/1000 ) + getpid(); + #endif + + if( _test ) + free( _test ); + + return _ret; +} +#endif // OAES_HAVE_ISAAC + +static OAES_RET oaes_key_destroy( oaes_key ** key ) +{ + if( NULL == *key ) + return OAES_RET_SUCCESS; + + if( (*key)->data ) + { + free( (*key)->data ); + (*key)->data = NULL; + } + + if( (*key)->exp_data ) + { + free( (*key)->exp_data ); + (*key)->exp_data = NULL; + } + + (*key)->data_len = 0; + (*key)->exp_data_len = 0; + (*key)->num_keys = 0; + (*key)->key_base = 0; + free( *key ); + *key = NULL; + + return OAES_RET_SUCCESS; +} + +static OAES_RET oaes_key_expand( OAES_CTX * ctx ) +{ + size_t _i, _j; + oaes_ctx * _ctx = (oaes_ctx *) ctx; + + if( NULL == _ctx ) + return OAES_RET_ARG1; + + if( NULL == _ctx->key ) + return OAES_RET_NOKEY; + + _ctx->key->key_base = _ctx->key->data_len / OAES_RKEY_LEN; + _ctx->key->num_keys = _ctx->key->key_base + OAES_ROUND_BASE; + + _ctx->key->exp_data_len = _ctx->key->num_keys * OAES_RKEY_LEN * OAES_COL_LEN; + _ctx->key->exp_data = (uint8_t *) + calloc( _ctx->key->exp_data_len, sizeof( uint8_t )); + + if( NULL == _ctx->key->exp_data ) + return OAES_RET_MEM; + + // the first _ctx->key->data_len are a direct copy + memcpy( _ctx->key->exp_data, _ctx->key->data, _ctx->key->data_len ); + + // apply ExpandKey algorithm for remainder + for( _i = _ctx->key->key_base; _i < _ctx->key->num_keys * OAES_RKEY_LEN; _i++ ) + { + uint8_t _temp[OAES_COL_LEN]; + + memcpy( _temp, + _ctx->key->exp_data + ( _i - 1 ) * OAES_RKEY_LEN, OAES_COL_LEN ); + + // transform key column + if( 0 == _i % _ctx->key->key_base ) + { + oaes_word_rot_left( _temp ); + + for( _j = 0; _j < OAES_COL_LEN; _j++ ) + oaes_sub_byte( _temp + _j ); + + _temp[0] = _temp[0] ^ oaes_gf_8[ _i / _ctx->key->key_base - 1 ]; + } + else if( _ctx->key->key_base > 6 && 4 == _i % _ctx->key->key_base ) + { + for( _j = 0; _j < OAES_COL_LEN; _j++ ) + oaes_sub_byte( _temp + _j ); + } + + for( _j = 0; _j < OAES_COL_LEN; _j++ ) + { + _ctx->key->exp_data[ _i * OAES_RKEY_LEN + _j ] = + _ctx->key->exp_data[ ( _i - _ctx->key->key_base ) * + OAES_RKEY_LEN + _j ] ^ _temp[_j]; + } + } + + return OAES_RET_SUCCESS; +} + +static OAES_RET oaes_key_gen( OAES_CTX * ctx, size_t key_size ) +{ + size_t _i; + oaes_key * _key = NULL; + oaes_ctx * _ctx = (oaes_ctx *) ctx; + OAES_RET _rc = OAES_RET_SUCCESS; + + if( NULL == _ctx ) + return OAES_RET_ARG1; + + _key = (oaes_key *) calloc( sizeof( oaes_key ), 1 ); + + if( NULL == _key ) + return OAES_RET_MEM; + + if( _ctx->key ) + oaes_key_destroy( &(_ctx->key) ); + + _key->data_len = key_size; + _key->data = (uint8_t *) calloc( key_size, sizeof( uint8_t )); + + if( NULL == _key->data ) + { + free( _key ); + return OAES_RET_MEM; + } + + for( _i = 0; _i < key_size; _i++ ) +#ifdef OAES_HAVE_ISAAC + _key->data[_i] = (uint8_t) rand( _ctx->rctx ); +#else + _key->data[_i] = (uint8_t) rand(); +#endif // OAES_HAVE_ISAAC + + _ctx->key = _key; + _rc = _rc || oaes_key_expand( ctx ); + + if( _rc != OAES_RET_SUCCESS ) + { + oaes_key_destroy( &(_ctx->key) ); + return _rc; + } + + return OAES_RET_SUCCESS; +} + +OAES_RET oaes_key_gen_128( OAES_CTX * ctx ) +{ + return oaes_key_gen( ctx, 16 ); +} + +OAES_RET oaes_key_gen_192( OAES_CTX * ctx ) +{ + return oaes_key_gen( ctx, 24 ); +} + +OAES_RET oaes_key_gen_256( OAES_CTX * ctx ) +{ + return oaes_key_gen( ctx, 32 ); +} + +OAES_RET oaes_key_export( OAES_CTX * ctx, + uint8_t * data, size_t * data_len ) +{ + size_t _data_len_in; + oaes_ctx * _ctx = (oaes_ctx *) ctx; + + if( NULL == _ctx ) + return OAES_RET_ARG1; + + if( NULL == _ctx->key ) + return OAES_RET_NOKEY; + + if( NULL == data_len ) + return OAES_RET_ARG3; + + _data_len_in = *data_len; + // data + header + *data_len = _ctx->key->data_len + OAES_BLOCK_SIZE; + + if( NULL == data ) + return OAES_RET_SUCCESS; + + if( _data_len_in < *data_len ) + return OAES_RET_BUF; + + // header + memcpy( data, oaes_header, OAES_BLOCK_SIZE ); + data[5] = 0x01; + data[7] = _ctx->key->data_len; + memcpy( data + OAES_BLOCK_SIZE, _ctx->key->data, _ctx->key->data_len ); + + return OAES_RET_SUCCESS; +} + +OAES_RET oaes_key_export_data( OAES_CTX * ctx, + uint8_t * data, size_t * data_len ) +{ + size_t _data_len_in; + oaes_ctx * _ctx = (oaes_ctx *) ctx; + + if( NULL == _ctx ) + return OAES_RET_ARG1; + + if( NULL == _ctx->key ) + return OAES_RET_NOKEY; + + if( NULL == data_len ) + return OAES_RET_ARG3; + + _data_len_in = *data_len; + *data_len = _ctx->key->data_len; + + if( NULL == data ) + return OAES_RET_SUCCESS; + + if( _data_len_in < *data_len ) + return OAES_RET_BUF; + + memcpy( data, _ctx->key->data, *data_len ); + + return OAES_RET_SUCCESS; +} + +OAES_RET oaes_key_import( OAES_CTX * ctx, + const uint8_t * data, size_t data_len ) +{ + oaes_ctx * _ctx = (oaes_ctx *) ctx; + OAES_RET _rc = OAES_RET_SUCCESS; + int _key_length; + + if( NULL == _ctx ) + return OAES_RET_ARG1; + + if( NULL == data ) + return OAES_RET_ARG2; + + switch( data_len ) + { + case 16 + OAES_BLOCK_SIZE: + case 24 + OAES_BLOCK_SIZE: + case 32 + OAES_BLOCK_SIZE: + break; + default: + return OAES_RET_ARG3; + } + + // header + if( 0 != memcmp( data, oaes_header, 4 ) ) + return OAES_RET_HEADER; + + // header version + switch( data[4] ) + { + case 0x01: + break; + default: + return OAES_RET_HEADER; + } + + // header type + switch( data[5] ) + { + case 0x01: + break; + default: + return OAES_RET_HEADER; + } + + // options + _key_length = data[7]; + switch( _key_length ) + { + case 16: + case 24: + case 32: + break; + default: + return OAES_RET_HEADER; + } + + if( (int)data_len != _key_length + OAES_BLOCK_SIZE ) + return OAES_RET_ARG3; + + if( _ctx->key ) + oaes_key_destroy( &(_ctx->key) ); + + _ctx->key = (oaes_key *) calloc( sizeof( oaes_key ), 1 ); + + if( NULL == _ctx->key ) + return OAES_RET_MEM; + + _ctx->key->data_len = _key_length; + _ctx->key->data = (uint8_t *) + calloc( _key_length, sizeof( uint8_t )); + + if( NULL == _ctx->key->data ) + { + oaes_key_destroy( &(_ctx->key) ); + return OAES_RET_MEM; + } + + memcpy( _ctx->key->data, data + OAES_BLOCK_SIZE, _key_length ); + _rc = _rc || oaes_key_expand( ctx ); + + if( _rc != OAES_RET_SUCCESS ) + { + oaes_key_destroy( &(_ctx->key) ); + return _rc; + } + + return OAES_RET_SUCCESS; +} + +OAES_RET oaes_key_import_data( OAES_CTX * ctx, + const uint8_t * data, size_t data_len ) +{ + oaes_ctx * _ctx = (oaes_ctx *) ctx; + OAES_RET _rc = OAES_RET_SUCCESS; + + if( NULL == _ctx ) + return OAES_RET_ARG1; + + if( NULL == data ) + return OAES_RET_ARG2; + + switch( data_len ) + { + case 16: + case 24: + case 32: + break; + default: + return OAES_RET_ARG3; + } + + if( _ctx->key ) + oaes_key_destroy( &(_ctx->key) ); + + _ctx->key = (oaes_key *) calloc( sizeof( oaes_key ), 1 ); + + if( NULL == _ctx->key ) + return OAES_RET_MEM; + + _ctx->key->data_len = data_len; + _ctx->key->data = (uint8_t *) + calloc( data_len, sizeof( uint8_t )); + + if( NULL == _ctx->key->data ) + { + oaes_key_destroy( &(_ctx->key) ); + return OAES_RET_MEM; + } + + memcpy( _ctx->key->data, data, data_len ); + _rc = _rc || oaes_key_expand( ctx ); + + if( _rc != OAES_RET_SUCCESS ) + { + oaes_key_destroy( &(_ctx->key) ); + return _rc; + } + + return OAES_RET_SUCCESS; +} + +OAES_CTX * oaes_alloc(void) +{ + oaes_ctx * _ctx = (oaes_ctx *) calloc( sizeof( oaes_ctx ), 1 ); + + if( NULL == _ctx ) + return NULL; + +#ifdef OAES_HAVE_ISAAC + { + ub4 _i = 0; + char _seed[RANDSIZ + 1]; + + _ctx->rctx = (randctx *) calloc( sizeof( randctx ), 1 ); + + if( NULL == _ctx->rctx ) + { + free( _ctx ); + return NULL; + } + + oaes_get_seed( _seed ); + memset( _ctx->rctx->randrsl, 0, RANDSIZ ); + memcpy( _ctx->rctx->randrsl, _seed, RANDSIZ ); + randinit( _ctx->rctx, TRUE); + } +#else + srand( oaes_get_seed() ); +#endif // OAES_HAVE_ISAAC + + _ctx->key = NULL; + oaes_set_option( _ctx, OAES_OPTION_CBC, NULL ); + +#ifdef OAES_DEBUG + _ctx->step_cb = NULL; + oaes_set_option( _ctx, OAES_OPTION_STEP_OFF, NULL ); +#endif // OAES_DEBUG + + return (OAES_CTX *) _ctx; +} + +OAES_RET oaes_free( OAES_CTX ** ctx ) +{ + oaes_ctx ** _ctx = (oaes_ctx **) ctx; + + if( NULL == _ctx ) + return OAES_RET_ARG1; + + if( NULL == *_ctx ) + return OAES_RET_SUCCESS; + + if( (*_ctx)->key ) + oaes_key_destroy( &((*_ctx)->key) ); + +#ifdef OAES_HAVE_ISAAC + if( (*_ctx)->rctx ) + { + free( (*_ctx)->rctx ); + (*_ctx)->rctx = NULL; + } +#endif // OAES_HAVE_ISAAC + + free( *_ctx ); + *_ctx = NULL; + + return OAES_RET_SUCCESS; +} + +OAES_RET oaes_set_option( OAES_CTX * ctx, + OAES_OPTION option, const void * value ) +{ + size_t _i; + oaes_ctx * _ctx = (oaes_ctx *) ctx; + + if( NULL == _ctx ) + return OAES_RET_ARG1; + + switch( option ) + { + case OAES_OPTION_ECB: + _ctx->options &= ~OAES_OPTION_CBC; + memset( _ctx->iv, 0, OAES_BLOCK_SIZE ); + break; + + case OAES_OPTION_CBC: + _ctx->options &= ~OAES_OPTION_ECB; + if( value ) + memcpy( _ctx->iv, value, OAES_BLOCK_SIZE ); + else + { + for( _i = 0; _i < OAES_BLOCK_SIZE; _i++ ) +#ifdef OAES_HAVE_ISAAC + _ctx->iv[_i] = (uint8_t) rand( _ctx->rctx ); +#else + _ctx->iv[_i] = (uint8_t) rand(); +#endif // OAES_HAVE_ISAAC + } + break; + +#ifdef OAES_DEBUG + + case OAES_OPTION_STEP_ON: + if( value ) + { + _ctx->options &= ~OAES_OPTION_STEP_OFF; + _ctx->step_cb = value; + } + else + { + _ctx->options &= ~OAES_OPTION_STEP_ON; + _ctx->options |= OAES_OPTION_STEP_OFF; + _ctx->step_cb = NULL; + return OAES_RET_ARG3; + } + break; + + case OAES_OPTION_STEP_OFF: + _ctx->options &= ~OAES_OPTION_STEP_ON; + _ctx->step_cb = NULL; + break; + +#endif // OAES_DEBUG + + default: + return OAES_RET_ARG2; + } + + _ctx->options |= option; + + return OAES_RET_SUCCESS; +} + +static OAES_RET oaes_encrypt_block( + OAES_CTX * ctx, uint8_t * c, size_t c_len ) +{ + size_t _i, _j; + oaes_ctx * _ctx = (oaes_ctx *) ctx; + + if( NULL == _ctx ) + return OAES_RET_ARG1; + + if( NULL == c ) + return OAES_RET_ARG2; + + if( c_len != OAES_BLOCK_SIZE ) + return OAES_RET_ARG3; + + if( NULL == _ctx->key ) + return OAES_RET_NOKEY; + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + _ctx->step_cb( c, "input", 1, NULL ); +#endif // OAES_DEBUG + + // AddRoundKey(State, K0) + for( _i = 0; _i < c_len; _i++ ) + c[_i] = c[_i] ^ _ctx->key->exp_data[_i]; + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + { + _ctx->step_cb( _ctx->key->exp_data, "k_sch", 1, NULL ); + _ctx->step_cb( c, "k_add", 1, NULL ); + } +#endif // OAES_DEBUG + + // for round = 1 step 1 to Nr–1 + for( _i = 1; _i < _ctx->key->num_keys - 1; _i++ ) + { + // SubBytes(state) + for( _j = 0; _j < c_len; _j++ ) + oaes_sub_byte( c + _j ); + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + _ctx->step_cb( c, "s_box", _i, NULL ); +#endif // OAES_DEBUG + + // ShiftRows(state) + oaes_shift_rows( c ); + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + _ctx->step_cb( c, "s_row", _i, NULL ); +#endif // OAES_DEBUG + + // MixColumns(state) + oaes_mix_cols( c ); + oaes_mix_cols( c + 4 ); + oaes_mix_cols( c + 8 ); + oaes_mix_cols( c + 12 ); + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + _ctx->step_cb( c, "m_col", _i, NULL ); +#endif // OAES_DEBUG + + // AddRoundKey(state, w[round*Nb, (round+1)*Nb-1]) + for( _j = 0; _j < c_len; _j++ ) + c[_j] = c[_j] ^ + _ctx->key->exp_data[_i * OAES_RKEY_LEN * OAES_COL_LEN + _j]; + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + { + _ctx->step_cb( _ctx->key->exp_data + _i * OAES_RKEY_LEN * OAES_COL_LEN, + "k_sch", _i, NULL ); + _ctx->step_cb( c, "k_add", _i, NULL ); + } +#endif // OAES_DEBUG + + } + + // SubBytes(state) + for( _i = 0; _i < c_len; _i++ ) + oaes_sub_byte( c + _i ); + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + _ctx->step_cb( c, "s_box", _ctx->key->num_keys - 1, NULL ); +#endif // OAES_DEBUG + + // ShiftRows(state) + oaes_shift_rows( c ); + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + _ctx->step_cb( c, "s_row", _ctx->key->num_keys - 1, NULL ); +#endif // OAES_DEBUG + + // AddRoundKey(state, w[Nr*Nb, (Nr+1)*Nb-1]) + for( _i = 0; _i < c_len; _i++ ) + c[_i] = c[_i] ^ _ctx->key->exp_data[ + ( _ctx->key->num_keys - 1 ) * OAES_RKEY_LEN * OAES_COL_LEN + _i ]; + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + { + _ctx->step_cb( _ctx->key->exp_data + + ( _ctx->key->num_keys - 1 ) * OAES_RKEY_LEN * OAES_COL_LEN, + "k_sch", _ctx->key->num_keys - 1, NULL ); + _ctx->step_cb( c, "output", _ctx->key->num_keys - 1, NULL ); + } +#endif // OAES_DEBUG + + return OAES_RET_SUCCESS; +} + +static OAES_RET oaes_decrypt_block( + OAES_CTX * ctx, uint8_t * c, size_t c_len ) +{ + size_t _i, _j; + oaes_ctx * _ctx = (oaes_ctx *) ctx; + + if( NULL == _ctx ) + return OAES_RET_ARG1; + + if( NULL == c ) + return OAES_RET_ARG2; + + if( c_len != OAES_BLOCK_SIZE ) + return OAES_RET_ARG3; + + if( NULL == _ctx->key ) + return OAES_RET_NOKEY; + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + _ctx->step_cb( c, "iinput", _ctx->key->num_keys - 1, NULL ); +#endif // OAES_DEBUG + + // AddRoundKey(state, w[Nr*Nb, (Nr+1)*Nb-1]) + for( _i = 0; _i < c_len; _i++ ) + c[_i] = c[_i] ^ _ctx->key->exp_data[ + ( _ctx->key->num_keys - 1 ) * OAES_RKEY_LEN * OAES_COL_LEN + _i ]; + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + { + _ctx->step_cb( _ctx->key->exp_data + + ( _ctx->key->num_keys - 1 ) * OAES_RKEY_LEN * OAES_COL_LEN, + "ik_sch", _ctx->key->num_keys - 1, NULL ); + _ctx->step_cb( c, "ik_add", _ctx->key->num_keys - 1, NULL ); + } +#endif // OAES_DEBUG + + for( _i = _ctx->key->num_keys - 2; _i > 0; _i-- ) + { + // InvShiftRows(state) + oaes_inv_shift_rows( c ); + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + _ctx->step_cb( c, "is_row", _i, NULL ); +#endif // OAES_DEBUG + + // InvSubBytes(state) + for( _j = 0; _j < c_len; _j++ ) + oaes_inv_sub_byte( c + _j ); + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + _ctx->step_cb( c, "is_box", _i, NULL ); +#endif // OAES_DEBUG + + // AddRoundKey(state, w[round*Nb, (round+1)*Nb-1]) + for( _j = 0; _j < c_len; _j++ ) + c[_j] = c[_j] ^ + _ctx->key->exp_data[_i * OAES_RKEY_LEN * OAES_COL_LEN + _j]; + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + { + _ctx->step_cb( _ctx->key->exp_data + _i * OAES_RKEY_LEN * OAES_COL_LEN, + "ik_sch", _i, NULL ); + _ctx->step_cb( c, "ik_add", _i, NULL ); + } +#endif // OAES_DEBUG + + // InvMixColums(state) + oaes_inv_mix_cols( c ); + oaes_inv_mix_cols( c + 4 ); + oaes_inv_mix_cols( c + 8 ); + oaes_inv_mix_cols( c + 12 ); + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + _ctx->step_cb( c, "im_col", _i, NULL ); +#endif // OAES_DEBUG + + } + + // InvShiftRows(state) + oaes_inv_shift_rows( c ); + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + _ctx->step_cb( c, "is_row", 1, NULL ); +#endif // OAES_DEBUG + + // InvSubBytes(state) + for( _i = 0; _i < c_len; _i++ ) + oaes_inv_sub_byte( c + _i ); + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + _ctx->step_cb( c, "is_box", 1, NULL ); +#endif // OAES_DEBUG + + // AddRoundKey(state, w[0, Nb-1]) + for( _i = 0; _i < c_len; _i++ ) + c[_i] = c[_i] ^ _ctx->key->exp_data[_i]; + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + { + _ctx->step_cb( _ctx->key->exp_data, "ik_sch", 1, NULL ); + _ctx->step_cb( c, "ioutput", 1, NULL ); + } +#endif // OAES_DEBUG + + return OAES_RET_SUCCESS; +} + +OAES_RET oaes_encrypt( OAES_CTX * ctx, + const uint8_t * m, size_t m_len, uint8_t * c, size_t * c_len ) +{ + size_t _i, _j, _c_len_in, _c_data_len; + size_t _pad_len = m_len % OAES_BLOCK_SIZE == 0 ? + 0 : OAES_BLOCK_SIZE - m_len % OAES_BLOCK_SIZE; + oaes_ctx * _ctx = (oaes_ctx *) ctx; + OAES_RET _rc = OAES_RET_SUCCESS; + uint8_t _flags = _pad_len ? OAES_FLAG_PAD : 0; + + if( NULL == _ctx ) + return OAES_RET_ARG1; + + if( NULL == m ) + return OAES_RET_ARG2; + + if( NULL == c_len ) + return OAES_RET_ARG5; + + _c_len_in = *c_len; + // data + pad + _c_data_len = m_len + _pad_len; + // header + iv + data + pad + *c_len = 2 * OAES_BLOCK_SIZE + m_len + _pad_len; + + if( NULL == c ) + return OAES_RET_SUCCESS; + + if( _c_len_in < *c_len ) + return OAES_RET_BUF; + + if( NULL == _ctx->key ) + return OAES_RET_NOKEY; + + // header + memcpy(c, oaes_header, OAES_BLOCK_SIZE ); + memcpy(c + 6, &_ctx->options, sizeof(_ctx->options)); + memcpy(c + 8, &_flags, sizeof(_flags)); + // iv + memcpy(c + OAES_BLOCK_SIZE, _ctx->iv, OAES_BLOCK_SIZE ); + // data + memcpy(c + 2 * OAES_BLOCK_SIZE, m, m_len ); + + for( _i = 0; _i < _c_data_len; _i += OAES_BLOCK_SIZE ) + { + uint8_t _block[OAES_BLOCK_SIZE]; + size_t _block_size = min( m_len - _i, OAES_BLOCK_SIZE ); + + memcpy( _block, c + 2 * OAES_BLOCK_SIZE + _i, _block_size ); + + // insert pad + for( _j = 0; _j < OAES_BLOCK_SIZE - _block_size; _j++ ) + _block[ _block_size + _j ] = _j + 1; + + // CBC + if( _ctx->options & OAES_OPTION_CBC ) + { + for( _j = 0; _j < OAES_BLOCK_SIZE; _j++ ) + _block[_j] = _block[_j] ^ _ctx->iv[_j]; + } + + _rc = _rc || + oaes_encrypt_block( ctx, _block, OAES_BLOCK_SIZE ); + memcpy( c + 2 * OAES_BLOCK_SIZE + _i, _block, OAES_BLOCK_SIZE ); + + if( _ctx->options & OAES_OPTION_CBC ) + memcpy( _ctx->iv, _block, OAES_BLOCK_SIZE ); + } + + return _rc; +} + +OAES_RET oaes_decrypt( OAES_CTX * ctx, + const uint8_t * c, size_t c_len, uint8_t * m, size_t * m_len ) +{ + size_t _i, _j, _m_len_in; + oaes_ctx * _ctx = (oaes_ctx *) ctx; + OAES_RET _rc = OAES_RET_SUCCESS; + uint8_t _iv[OAES_BLOCK_SIZE]; + uint8_t _flags; + OAES_OPTION _options; + + if( NULL == ctx ) + return OAES_RET_ARG1; + + if( NULL == c ) + return OAES_RET_ARG2; + + if( c_len % OAES_BLOCK_SIZE ) + return OAES_RET_ARG3; + + if( NULL == m_len ) + return OAES_RET_ARG5; + + _m_len_in = *m_len; + *m_len = c_len - 2 * OAES_BLOCK_SIZE; + + if( NULL == m ) + return OAES_RET_SUCCESS; + + if( _m_len_in < *m_len ) + return OAES_RET_BUF; + + if( NULL == _ctx->key ) + return OAES_RET_NOKEY; + + // header + if( 0 != memcmp( c, oaes_header, 4 ) ) + return OAES_RET_HEADER; + + // header version + switch( c[4] ) + { + case 0x01: + break; + default: + return OAES_RET_HEADER; + } + + // header type + switch( c[5] ) + { + case 0x02: + break; + default: + return OAES_RET_HEADER; + } + + // options + memcpy(&_options, c + 6, sizeof(_options)); + // validate that all options are valid + if( _options & ~( + OAES_OPTION_ECB + | OAES_OPTION_CBC +#ifdef OAES_DEBUG + | OAES_OPTION_STEP_ON + | OAES_OPTION_STEP_OFF +#endif // OAES_DEBUG + ) ) + return OAES_RET_HEADER; + if( ( _options & OAES_OPTION_ECB ) && + ( _options & OAES_OPTION_CBC ) ) + return OAES_RET_HEADER; + if( _options == OAES_OPTION_NONE ) + return OAES_RET_HEADER; + + // flags + memcpy(&_flags, c + 8, sizeof(_flags)); + // validate that all flags are valid + if( _flags & ~( + OAES_FLAG_PAD + ) ) + return OAES_RET_HEADER; + + // iv + memcpy( _iv, c + OAES_BLOCK_SIZE, OAES_BLOCK_SIZE); + // data + pad + memcpy( m, c + 2 * OAES_BLOCK_SIZE, *m_len ); + + for( _i = 0; _i < *m_len; _i += OAES_BLOCK_SIZE ) + { + if( ( _options & OAES_OPTION_CBC ) && _i > 0 ) + memcpy( _iv, c + OAES_BLOCK_SIZE + _i, OAES_BLOCK_SIZE ); + + _rc = _rc || + oaes_decrypt_block( ctx, m + _i, min( *m_len - _i, OAES_BLOCK_SIZE ) ); + + // CBC + if( _options & OAES_OPTION_CBC ) + { + for( _j = 0; _j < OAES_BLOCK_SIZE; _j++ ) + m[ _i + _j ] = m[ _i + _j ] ^ _iv[_j]; + } + } + + // remove pad + if( _flags & OAES_FLAG_PAD ) + { + int _is_pad = 1; + size_t _temp = (size_t) m[*m_len - 1]; + + if( _temp <= 0x00 || _temp > 0x0f ) + return OAES_RET_HEADER; + for( _i = 0; _i < _temp; _i++ ) + if( m[*m_len - 1 - _i] != _temp - _i ) + _is_pad = 0; + if( _is_pad ) + { + memset( m + *m_len - _temp, 0, _temp ); + *m_len -= _temp; + } + else + return OAES_RET_HEADER; + } + + return OAES_RET_SUCCESS; +} + + +OAES_API OAES_RET oaes_encryption_round( const uint8_t * key, uint8_t * c ) +{ + size_t _i; + + if( NULL == key ) + return OAES_RET_ARG1; + + if( NULL == c ) + return OAES_RET_ARG2; + + // SubBytes(state) + for( _i = 0; _i < OAES_BLOCK_SIZE; _i++ ) + oaes_sub_byte( c + _i ); + + // ShiftRows(state) + oaes_shift_rows( c ); + + // MixColumns(state) + oaes_mix_cols( c ); + oaes_mix_cols( c + 4 ); + oaes_mix_cols( c + 8 ); + oaes_mix_cols( c + 12 ); + + // AddRoundKey(State, key) + for( _i = 0; _i < OAES_BLOCK_SIZE; _i++ ) + c[_i] ^= key[_i]; + + return OAES_RET_SUCCESS; +} + +OAES_API OAES_RET oaes_pseudo_encrypt_ecb( OAES_CTX * ctx, uint8_t * c ) +{ + size_t _i; + oaes_ctx * _ctx = (oaes_ctx *) ctx; + + if( NULL == _ctx ) + return OAES_RET_ARG1; + + if( NULL == c ) + return OAES_RET_ARG2; + + if( NULL == _ctx->key ) + return OAES_RET_NOKEY; + + for ( _i = 0; _i < 10; ++_i ) + { + oaes_encryption_round( &_ctx->key->exp_data[_i * OAES_RKEY_LEN * OAES_COL_LEN], c ); + } + + return OAES_RET_SUCCESS; +} diff --git a/monero_crypto/oaes_lib.h b/monero_crypto/oaes_lib.h new file mode 100644 index 0000000000..fd1942822a --- /dev/null +++ b/monero_crypto/oaes_lib.h @@ -0,0 +1,215 @@ +/* + * --------------------------------------------------------------------------- + * 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_LIB_H +#define _OAES_LIB_H + +#include <stdint.h> +#include <stdlib.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _WIN32 +# ifdef OAES_SHARED +# ifdef oaes_lib_EXPORTS +# define OAES_API __declspec(dllexport) +# else +# define OAES_API __declspec(dllimport) +# endif +# else +# define OAES_API +# endif +#else +# define OAES_API +#endif // WIN32 + +#define OAES_VERSION "0.8.1" +#define OAES_BLOCK_SIZE 16 + +typedef void OAES_CTX; + +typedef enum +{ + OAES_RET_FIRST = 0, + OAES_RET_SUCCESS = 0, + OAES_RET_UNKNOWN, + OAES_RET_ARG1, + OAES_RET_ARG2, + OAES_RET_ARG3, + OAES_RET_ARG4, + OAES_RET_ARG5, + OAES_RET_NOKEY, + OAES_RET_MEM, + OAES_RET_BUF, + OAES_RET_HEADER, + OAES_RET_COUNT +} OAES_RET; + +/* + * oaes_set_option() takes one of these values for its [option] parameter + * some options accept either an optional or a required [value] parameter + */ +// no option +#define OAES_OPTION_NONE 0 +// enable ECB mode, disable CBC mode +#define OAES_OPTION_ECB 1 +// enable CBC mode, disable ECB mode +// value is optional, may pass uint8_t iv[OAES_BLOCK_SIZE] to specify +// the value of the initialization vector, iv +#define OAES_OPTION_CBC 2 + +#ifdef OAES_DEBUG +typedef int ( * oaes_step_cb ) ( + const uint8_t state[OAES_BLOCK_SIZE], + const char * step_name, + int step_count, + void * user_data ); +// enable state stepping mode +// value is required, must pass oaes_step_cb to receive the state at each step +#define OAES_OPTION_STEP_ON 4 +// disable state stepping mode +#define OAES_OPTION_STEP_OFF 8 +#endif // OAES_DEBUG + +typedef uint16_t OAES_OPTION; + +typedef struct _oaes_key +{ + size_t data_len; + uint8_t *data; + size_t exp_data_len; + uint8_t *exp_data; + size_t num_keys; + size_t key_base; +} oaes_key; + +typedef struct _oaes_ctx +{ +#ifdef OAES_HAVE_ISAAC + randctx * rctx; +#endif // OAES_HAVE_ISAAC + +#ifdef OAES_DEBUG + oaes_step_cb step_cb; +#endif // OAES_DEBUG + + oaes_key * key; + OAES_OPTION options; + uint8_t iv[OAES_BLOCK_SIZE]; +} oaes_ctx; +/* + * // usage: + * + * OAES_CTX * ctx = oaes_alloc(); + * . + * . + * . + * { + * oaes_gen_key_xxx( ctx ); + * { + * oaes_key_export( ctx, _buf, &_buf_len ); + * // or + * oaes_key_export_data( ctx, _buf, &_buf_len );\ + * } + * } + * // or + * { + * oaes_key_import( ctx, _buf, _buf_len ); + * // or + * oaes_key_import_data( ctx, _buf, _buf_len ); + * } + * . + * . + * . + * oaes_encrypt( ctx, m, m_len, c, &c_len ); + * . + * . + * . + * oaes_decrypt( ctx, c, c_len, m, &m_len ); + * . + * . + * . + * oaes_free( &ctx ); + */ + +OAES_API OAES_CTX * oaes_alloc(void); + +OAES_API OAES_RET oaes_free( OAES_CTX ** ctx ); + +OAES_API OAES_RET oaes_set_option( OAES_CTX * ctx, + OAES_OPTION option, const void * value ); + +OAES_API OAES_RET oaes_key_gen_128( OAES_CTX * ctx ); + +OAES_API OAES_RET oaes_key_gen_192( OAES_CTX * ctx ); + +OAES_API OAES_RET oaes_key_gen_256( OAES_CTX * ctx ); + +// export key with header information +// set data == NULL to get the required data_len +OAES_API OAES_RET oaes_key_export( OAES_CTX * ctx, + uint8_t * data, size_t * data_len ); + +// directly export the data from key +// set data == NULL to get the required data_len +OAES_API OAES_RET oaes_key_export_data( OAES_CTX * ctx, + uint8_t * data, size_t * data_len ); + +// import key with header information +OAES_API OAES_RET oaes_key_import( OAES_CTX * ctx, + const uint8_t * data, size_t data_len ); + +// directly import data into key +OAES_API OAES_RET oaes_key_import_data( OAES_CTX * ctx, + const uint8_t * data, size_t data_len ); + +// set c == NULL to get the required c_len +OAES_API OAES_RET oaes_encrypt( OAES_CTX * ctx, + const uint8_t * m, size_t m_len, uint8_t * c, size_t * c_len ); + +// set m == NULL to get the required m_len +OAES_API OAES_RET oaes_decrypt( OAES_CTX * ctx, + const uint8_t * c, size_t c_len, uint8_t * m, size_t * m_len ); + +// set buf == NULL to get the required buf_len +OAES_API OAES_RET oaes_sprintf( + char * buf, size_t * buf_len, const uint8_t * data, size_t data_len ); + +OAES_API OAES_RET oaes_encryption_round( const uint8_t * key, uint8_t * c ); + +OAES_API OAES_RET oaes_pseudo_encrypt_ecb( OAES_CTX * ctx, uint8_t * c ); + +#ifdef __cplusplus +} +#endif + +#endif // _OAES_LIB_H diff --git a/monero_crypto/random.c b/monero_crypto/random.c new file mode 100644 index 0000000000..691c31f624 --- /dev/null +++ b/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/monero_crypto/random.h b/monero_crypto/random.h new file mode 100644 index 0000000000..75d23fd04d --- /dev/null +++ b/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/monero_crypto/skein.c b/monero_crypto/skein.c new file mode 100644 index 0000000000..65e4525c33 --- /dev/null +++ b/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/monero_crypto/skein.h b/monero_crypto/skein.h new file mode 100644 index 0000000000..5c9cc55183 --- /dev/null +++ b/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/monero_crypto/skein_port.h b/monero_crypto/skein_port.h new file mode 100644 index 0000000000..a06ef30a26 --- /dev/null +++ b/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/monero_crypto/slow-hash.c b/monero_crypto/slow-hash.c new file mode 100644 index 0000000000..cc234713b8 --- /dev/null +++ b/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/monero_crypto/tree-hash.c b/monero_crypto/tree-hash.c new file mode 100644 index 0000000000..eb98c31b78 --- /dev/null +++ b/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); + } +} diff --git a/monero_crypto/warnings.h b/monero_crypto/warnings.h new file mode 100644 index 0000000000..196434db13 --- /dev/null +++ b/monero_crypto/warnings.h @@ -0,0 +1,33 @@ +#ifndef _WARNINGS_H_ +#define _WARNINGS_H_ + +#if defined(_MSC_VER) + +#define PUSH_WARNINGS __pragma(warning(push)) +#define POP_WARNINGS __pragma(warning(pop)) +#define DISABLE_VS_WARNINGS(w) __pragma(warning(disable: w)) +#define DISABLE_GCC_WARNING(w) +#define DISABLE_CLANG_WARNING(w) +#define DISABLE_GCC_AND_CLANG_WARNING(w) + +#else + +#include <boost/preprocessor/stringize.hpp> + +#define PUSH_WARNINGS _Pragma("GCC diagnostic push") +#define POP_WARNINGS _Pragma("GCC diagnostic pop") +#define DISABLE_VS_WARNINGS(w) + +#if defined(__clang__) +#define DISABLE_GCC_WARNING(w) +#define DISABLE_CLANG_WARNING DISABLE_GCC_AND_CLANG_WARNING +#else +#define DISABLE_GCC_WARNING DISABLE_GCC_AND_CLANG_WARNING +#define DISABLE_CLANG_WARNING(w) +#endif + +#define DISABLE_GCC_AND_CLANG_WARNING(w) _Pragma(BOOST_PP_STRINGIZE(GCC diagnostic ignored BOOST_PP_STRINGIZE(-W##w))) + +#endif + +#endif -- GitLab